はじめに
Rails では RESTful な設計とするために各種 HTTP リクエストメソッドを使い分けていて、config/routes.rb
では当たり前に DELETE メソッドを定義すると思います。
が、このルーティング、正しく機能するためには条件があります。その条件を満たしていないと正しく動作しません。
結論
jquery-ujs.js
もしくは rails-ujs.js
が読み込まれていることが条件です。これら JavaScript が__トリックによって DELETE をエミュレート__しています。
トリックの正体と有効/無効
一般的にブラウザでは GET と POST しか使えません。DELETE リクエストは送信されないので、当該ルートが発現することはありません。例えば link_to method: :delete
と書いたとしてもブラウザの素の能力では GET が送信されてしまい、最悪誤動作を引き起こします。
そこで前述 JavaScript が上手いことやって「DELETE のつもりでリクエストするんだぜ」というのを伝えることで、DELETE メソッドではないものの DELETE ルートを発現させています。具体的には form オブジェクトを作って「本来の意図は DELETE だよ」というパラメータを添えて POST しています。
そしてこのトリックは普通に rails new
すれば自動的にお膳立てされ有効になります。
が、rails new --skip-javascript
すると無効になります。JavaScript に依存しているんだから当たり前ですね。そして前述のように link_to method: :delete
は GET になってしまうのです。
手作業でトリックを有効にする方法
何らかの事情で rails new --skip-javascript
しなければならない場合に手作業でトリックを有効にする方法は、下記です。各ファイルに各行を追記します。
//= require rails-ujs
<%= javascript_include_tag 'application' %>
別法あります
ここまでは前置きです。
ここからが本題です。
JavaScript を使わなくても DELETE ルートを使うことは出来ます。button_to method: :delete
です。
JavaScript が生成している form を静的に生成すればいいわけです。
より link_to ぽく
button_to では input type='submit'
が1つ(と input type='hidden'
が幾つか)の form が生成されますが、class='button_to'
になっています。さらに例えば button_to class: :anchor
とすると input type='submit' class='anchor'
になります。
<form class="button_to" method="post" action="/logout">
<input type="hidden" name="_method" value="delete" />
<input type="hidden" name="authenticity_token" value="ナイショ" />
<input class="anchor" type="submit" value="LOGOUT" />
</form>
なので、下記のような CSS (SCSS) を書いてやれば、機能も見た目も link_to の代わりに使うことが可能です。
form.button_to {
display: inline;
input.anchor[type='submit'] {
border-style: none;
padding: 0;
font-size: 1em;
cursor: pointer;
background-color: $bg-color;
color: $link-color;
}
}
終わりに
もともと --skip-javascript なんて使ってなかったんですが、Rails 6 が Webpacker で yarn や node_modules 必須になってたものの取り急ぎ小さく new したかったので --skip-javascript したら一旦良さそうだったけど logout 出来ず「!?」となって、、、ここに至りました。
静的最高♪