ログアウトできない。RoutingErrorにハマった話
こんにちは、Rails学習中の者です。
転職用のポートフォリオを作成している中で、Deviseを使った認証機能を実装していたところ
「ログアウトボタンを押したらRoutingError」
という落とし穴にハマりました。
この記事では、実際に経験したエラーとその原因、その際の解決方法をまとめておきます。
発生したエラー
<%= link_to 'ログアウト', destroy_user_session_path, method: :delete, class: 'btn btn-pink btn-sm' %>
このコードを使っていたとき、ログアウトリンクをクリックした際にエラー表示
Routing Error: No route matches [GET] "/users/sign_out"
エラーの原因
リンクがmethod: :deleteでDELETE /users/sign_outを送るように指定しているのに、
実際のブラウザ上ではGETリクエストが送られてしまっていた ことが原因です。
なぜGETに変わってしまった?
Railsではmethod: :deleteを使ったリンクは、内部的にJavaScript(UJSまたはTurboが必要です。
- ページに必要なJavaScriptが読み込まれていない
- または、
turboが有効でlink_toではmethod: :deleteが効いていない
このどちらかが原因で、意図したDELETEが送れずGETにフォールバック → ルーティングエラー になっていました。
一時的な対策:button_toを使う
<%= button_to 'ログアウト', destroy_user_session_path, method: :delete, class: 'btn btn-pink btn-sm' %>
これでフォームとしてDELETEリクエストが送られるため、確実にログアウトが動作しました。
ただ、ボタンの見た目が変わることがありました。
最終的な解決策:link_to+Turbo対応
<%= link_to 'ログアウト', destroy_user_session_path, data: { turbo_method: :delete }, class: 'btn btn-pink btn-sm' %>
Rails7以降、Turboが標準になったことでmethod: :delete単体では動作しないケースがあるそうです。
そのため、data: { turbo_method: :delete } を明示的に指定することで対応できました。
学んだこと
-
link_toにmethod: :deleteを使う場合、JSが必要(UJS or Turbo) - Rails7では
Turboが効いてるので、data: { turbo_method: :delete }を忘れない - よくわからないときは
button_toにするのも手
最後に
今回の件は、「Railsのルーティングが悪い」のではなく、JavaScriptとHTTPメソッドの連携の理解不足が原因でした。
初心者のうちはmethod: :deleteと書いただけで安心しがちですが、ブラウザ側で実際にどう動くのかまで見てみると理解につながるため、引き続き注意していきたいです。