はじめに
過去記事にてボタンを押しても反応しなくて、少しだけ詳細をお伝えしていた、と思いますが、解決したので改めて記事にまとめてみようと思います
環境
- Windows, WSL
- Docker
- Ruby 3.2.3
- Rails 7.1.3
状況
表題にもありますようになぜかログアウトボタンをおしても反応しない状態でした。
教えていただいたヒントから色々確認
- 確認:dockerログ。controllers/user_sessions_controller。config/routes.rb。どれも記述コード問題なさそう
- 改めて起きている問題について:Webサイズの「ログアウト」ボタンコードの処理は反応している=つまり、turboは動いてはいるがリクエストの通り方がGETだけになっている。(ログからわかる)
試し1:ビルドしなおす
docker compose down してからdocker compose build --no-cache。完了したら改めてdocker compose up
ログアウトボタンは反応せず( ;∀;)
試し2:コードを変えてみる
Web幅変更前:<li class="hidden md:block link link-hover"><%= link_to "ログアウト", logout_path, method: :delete, data: { confirm: "ログアウトしますか?" } %></li>
Web幅変更後:<li class="hidden md:block link link-hover"><%= link_to "ログアウト", logout_path, data: { turbo_method: :delete } %></li>
スマホ幅はそのまま:<li class="md:hidden"><%= link_to "ログアウト", logout_path, data: { turbo_method: :delete } %></li>
Googleの開発者ツールConsoleチェック。map.getでエラーと表示されている?
turboがうまく動いていなくてとりあえずgetをわたしている。
開発者ツールのConsoleのエラーの詳細
# エラー詳細1つ目
application-f50ea9f12f34680baf709b4508e2968b4ac8319d238ec62c3278e4f4a0511a99.js:3312
TypeError: map.get is not a function
at fetch (application-f50ea9f12f34680baf709b4508e2968b4ac8319d238ec62c3278e4f4a0511a99.js:6371:20)
at fetchWithTurboHeaders (application-f50ea9f12f34680baf709b4508e2968b4ac8319d238ec62c3278e4f4a0511a99.js:1147:10)
at FetchRequest.perform (application-f50ea9f12f34680baf709b4508e2968b4ac8319d238ec62c3278e4f4a0511a99.js:1257:25)
# エラー詳細2つめ
application-f50ea9f1…4f4a0511a99.js:6371 Uncaught (in promise)
TypeError: map.get is not a function
at fetch (application-f50ea9f1…a0511a99.js:6371:20)
at fetchWithTurboHeaders (application-f50ea9f1…a0511a99.js:1147:10)
at FetchRequest.perform (application-f50ea9f1…a0511a99.js:1257:25)
- エラー内容の理解
fetch
関数が実行されたときに、何らかの理由でJavaScriptのmap
オブジェクトが期待された形ではなく、get
関数を持たないオブジェクトが使われたためにエラーが発生している - エラー1つ目
fetch
関数が実行されたときに発生。fetch
関数は通常、Webサーバーからデータを取得するために使われるが、fetch
関数が内部でmap.get
を呼び出そうとしたとき、map
がget
関数を持っていない(つまり、map
が正しい型のオブジェクトでない)ため、エラーが発生!!これにより、サーバーへのリクエストが正しく処理されていない - エラー2つ目
1つ目のエラーと同じ内容だが、Uncaught (in promise)
という部分が追加。これは、JavaScriptの「Promise」という非同期処理を扱う仕組みの中でエラーが発生し、そのエラーがキャッチ(処理)されずにそのまま外部に出てしまったことを意味している。これにより、ログアウトボタンをクリックしたときに想定した動作が行われない原因になっている可能性がある!! - 解決策の方向性
エラー解決には、fetch
関数が正しいmap
オブジェクトを受け取っているかを確認!!問題の根本的な原因は、TurboやStimulusなどのJavaScriptライブラリが正しく動作していない、もしくは不適切なオブジェクトを渡している可能性がある!!
参考記事より修正を試みて、うごいた!!
Rails, Turbo, esbuild: TypeError: map.get is not a function
背景: defer
属性と type: "module"
の違い
-
defer
属性:-
defer
は、JavaScript ファイルが非同期で読み込まれ、HTML ドキュメントの解析が完了した後に実行されるように指示。これにより、ページのレンダリングが遅れずに行われます。 - ただし、
defer
は通常の**スクリプト(ウェブページに機能を追加するための命令やコードの集まりJavascriptとか)**として扱われるため、モジュールの依存関係が考慮されません。
-
-
type: "module"
:-
type: "module"
を指定すると、そのスクリプトは ESモジュールとして扱われます。モジュールとは、他のスクリプトからコードをインポートしたりエクスポートしたりできる特別な形式です。 - モジュールとして読み込まれたスクリプトは、
defer
と同様に非同期で実行されますが、さらに重要な点として、モジュール間の依存関係が自動的に管理されます。これにより、必要なコードが正しい順序で実行されます。
-
問題の原因と解決
Turbo
や Stimulus
のような最新のフレームワークは、内部的に ESモジュールを利用して依存関係を管理しています。しかし、defer
だけでスクリプトを読み込むと、これらの依存関係が正しく解決されないことがあります。結果として、fetch
関数などが期待通りに動作せず、map.get
のエラーが発生していました。
type: "module"
を指定することで、ブラウザはスクリプトをモジュールとして認識し、TurboやStimulusが必要とする依存関係を正しい順序で解決します。これにより、fetch
関数が正しく動作し、map.get
エラーが発生しなくなったのです。
簡単に言うと
-
defer
だけだと、JavaScript の実行順序や依存関係が正しく管理されず、エラーが発生することがあります。 -
type: "module"
を使うと、ブラウザが自動的に依存関係を管理し、JavaScript が期待通りに動作するようになります。 - これが理由で、ログアウトボタンが正しく機能するようになったのです!!
さいごに
思ってもみなかったところを修正したことで無事にエラー解決しました。やはり自分だけで解決しようとしても見る範囲が狭まってしまうので周りに助けを求めることはとても大切。視野を広くしてエラー解決の手段を色々身に着けられるようにしたいところです。