マトリョーシカ的日常

ワクワクばらまく明日のブログ。

Rails7のimport maps が反映されなかったので対応していた

子供達の本で占拠されていた机を整理して、本をそれぞれのところに戻した。同様に私の本棚たちを整理していたら懐かしいタイトルばかり出てきて、気分が良くなった。この書斎も最近は使わなくなってしまったが、いつか自分のもとに戻したい。

どうでも良いことを書いていた。

起こり

 Railsを使ったウェブアプリケーションを作っているが、データベースへの登録時に同じデータがふたつ登録されることがわかった。ずっとそうなっている。調べるとJavaScriptとimport mapsが関係していることがわかった。ちょっと複雑な関係であるため、こういって文章に残しておきたい。

データベースへ登録される構造

 データベースへ情報を登録する際に入力フォームを生成させる必要がある。Railsではform_with というメソッドを使うことで、うまいことデータベースへ送る仕組みを有するフォームが生成される。単純に入力フォームを作るだけではこうはいかない。

 しかし、私はこれに一手間加えた。あるJavaScriptの変数の値を一緒に送信させないといけない。そうなってくるとform_with を使うだけではダメで、JavaScriptも書かないといけない。

document.addEventListener("turbo:load", () => {
  const saveSimulationButton = document.getElementById("savesimulation");
  if (saveSimulationButton) {
    saveSimulationButton.addEventListener("click", (event) => {
      event.preventDefault();
      const form = document.getElementById("simulationForm");
      const formData = new FormData(form);
      formData.append("js_facilities", JSON.stringify(facilities));

      fetch(form.action, {
        method: "POST",
        headers: {
          "X-CSRF-Token": document
            .querySelector("meta[name='csrf-token']")
            .getAttribute("content"),
          Accept: "application/json",
        },
        body: formData,
      })
        .then((response) => response.json())
        .then((data) => {
          console.log("Success:", data);
          // 成功時の処理(ページ遷移など)
          window.location.href = data.location;
        })
        .catch((error) => {
          console.error("Error:", error);
          // エラー時の処理
        });
    });
  }
});

(ハイライトを使うと目がチカチカする) 入力フォームの後に書き込みボタンを作成し、そのボタンが押された時にイベントを.addEventListener("click",.. 以下に書き込む。

fetch(form.action, { method: "POST", ... がデータベースへ情報を書き込む処理である。これが二回行われているのが今回の問題であった。

二回書き込みが行われている原因

 開発ツールを開き、動作中の中身を確認した。どうやら同じ内容のJavaScriptファイルが二つできているようだ。ひとつは純粋なsimulation.js もうひとつはsimulation-aec15f2bcbbb92d677fba81f8b77ba38d8dff9c3b276db0e67fc4ae43f954f56.js というよくわからない名前になっているファイル。この二つのファイルに同じ処理が書かれているため、書き込みボタンを一度押すだけで二度の処理が行われているのだった。

長い名前のファイルは何か

 長いファイルはアセットパイプラインによって生成されるファイルだ。アセットパイプラインとはRailsでJavaScriptやCSSを提供するときに使うフレームワークである。この機能の一つとしてファイル名に長い名前(フィンガープリント)をつけるというものがある。フィンガープリントはファイルの中身が更新されると自動的に変わる。そうやって変化したかを確認している。

アセットパイプライン - Railsガイド

なぜファイルがふたつ生成されるのか

 これは本当にわからないままだった。ただ解決方法はわかった。

解決方法

javascript - How to add custom JS file to new rails 7 project - Stack Overflow

Do not precompile in development, it will serve precompiled assets from public/assets which do not update when you make changes. Run bin/rails assets:clobber to remove precompiled assets.

そういうわけで一旦rails assets:clobber を実行してプリコンパイルされたアセットを削除した。その後 rails s を実行する。 (The asset "tailwind.css" is not present in the asset pipeline." というエラーが出たのでもう一度コンパイルする。 そうしてrails assets:precompile を実行しプリコンパイルを再度行う。

こうして解決した。

結局何が悪かったか

TailwindCSSを使うのがよくなかったのかもしれない。

アセットパイプライン - Railsガイド

本ガイドでは、CSSの処理にsprocketsを、JavaScriptの処理にimportmap-railsのみを利用するデフォルトのアセットパイプラインに重点を置いています。この2つの主な制限は、トランスパイルをサポートしていないため、Babel、TypeScript、Sass、React JSX format、Tailwind CSSといったものが使えないことです。JavaScriptやCSSのトランスパイルが必要な場合は、「別のライブラリを使う」セクションをお読みください。

TailwindCSSをやるにはもっと最適なやり方があるのだろう。これはまたどこかで書く。

Unsplash Marek Piwnicki