ログアウトできない。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
と書いただけで安心しがちですが、ブラウザ側で実際にどう動くのかまで見てみると理解につながるため、引き続き注意していきたいです。