【Rails】link_toでdeleteが効かない時の解決方法


最近たまにある現象

・link_toで実装した削除ボタンが正常に動かない
・deviseを使用したログアウト機能でUsersコントローラーのshowアクションが動く

どちらも、HTTPメソッドにDELETEを指定しているにもかかわらずGETでリクエストが送られていることが原因でした。

※メソッドの指定はできている状態の話です。まずは検証ツールでHTMLを確認します。

<a data-method="delete" href="/users/sign_out">ログアウト</a>

結論

head間は触らないほうがいいです。

rails newコマンドでアプリを作成した際、レイアウトファイル(application.html.erb)内のhead間には以下の記述がデフォルトであるはずです。
一見意味がわかりませんが、消さないでください。まとめて貼れば解決します。

application.html.erb
  <head>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

今回必要だった記述は2行

application.jsの読み込み

application.html.erb
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>

application.jsを読み込んでいます。これでdeleteメソッドが効くようにはなります。

CSRF対策

CSRF(クロスサイトリクエストフォージェリ)対策の以下の記述をします。
これがないと意図しないリクエストを受信してしまいます。脆弱性です。

application.html.erb
<%= csrf_meta_tags %>

これがないとこんなエラーが出ます。

Railsのルールのようです。参考

解決しなかった場合

javascriptのrequireを記述する

app/assets/javascript/application.js内に以下を記述する。

application.js
//= require jquery
//= require jquery_ujs

jquery_ujsはハイパーリンクからGET以外のリクエストを生成してくれます。

なぜJSが必要か

HTMLで使えるHTTPメソッドはGETPOSTのみです。
今回使いたかったDELTEはjavascriptで擬似的に作成されるため、HTMLで読み込めなければ動きません。
詳しい動きはこちらが参考になります。

まとめ

携帯用ホムペの時代からhead間編集(上級者向け)だったことを覚えています。
これに限らず、デフォルトの記述を消す時は本当に大丈夫か一旦調べて考えてみてください。