- turboを利用していて、destroyアクションでリダイレクトを使うときステータスコードを明示的に303(see other)にしないと、リダイレクト先にDELETEメソッドでアクセスしてしまうというハマりポイントが有る
- 参考: Rails 7.0 + Ruby 3.1でゼロからアプリを作ってみたときにハマったところあれこれ #Ruby - Qiita
- 上記の例ではDELETEメソッドを利用しているけど、PATCH(PUT)でも同じ挙動になる
- Railsの現時点でのデフォルトのリダイレクト時は302なので、
redirect_to @project, status: :see_other
のように明示的にステータスコードを指定するとGETでリダイレクトする - なぜこのような仕様になっているかというと、fetch APIがそういう仕様だから
- fetch APIがなぜこのような仕様になっているかというと、302の仕様になるべく沿おうとしているから(要出典)
- 302 Found - HTTP | MDN
仕様書ではリダイレクトの際にメソッド (と本文) を変更しないよう要求していますが、すべてのユーザーエージェントが準拠している訳ではありません (まだこの種のバグのあるソフトウェアが見つかるでしょう)。従って、
302
コードはGET
またはHEAD
メソッドへのレスポンスのみに使用し、POST
メソッドのままリダイレクトする場合は代わりに307 Temporary Redirect
(こちらでは明確にメソッドの変更が禁止されている) を使用することが推奨されています。- chromeなどのブラウザでは、GETとPOST以外のメソッドでアクセスした場合は同じメソッドをリダイレクト先にも適用する、という実装になっている模様
- なので仕方ないっちゃ仕方ないんだけど、既存のアプリケーションに対してturboを採用しようとした場合には結構な負担になりますね
- Rails側はこの仕様を緩和するための変更がいくつか入っていたり提案されていたりする
- turbo-railsでは、PATCHやDELETEメソッドでリクエストするときにそれをPOSTと
_method
に差し替えるというロジックが入っている- Encode HTTP method into Request body as
_method
by seanpdoyle · Pull Request #370 · hotwired/turbo-rails - turbo-rails gemだとv1.3.0、@hotwired/turbo-rails npm だと7.2.0以降であればこのコミットが入っているので、意図しないリソースが削除されてしまう危険は回避されているはず
- しかしこれはあくまでTurbo発のリクエストだけを差し替えるので、独自にfetchを利用している箇所は依然として(GETでリダイレクトをしたければ)303でリダイレクトしてやる必要がある。
- Encode HTTP method into Request body as
- POST, PUT, DELETEなどのメソッドでリクエストが来たときのリダイレクト時のステータスコードを一律に設定させるための設定が提案されている
- Add
redirect_code_for_unsafe_http_methods
config by jonathanhefner · Pull Request #45393 · rails/rails - これ7.1に間に合ってほしかった…
- でも、これまで302で返しているものが303になったら古いアプリケーションにめっちゃ影響がありそうなので慎重になるのもわからなくはない
- Add
- scaffoldで生成されるアクションでは
status: :see_other
がつくようになっている(Rails7.1.0以降)- Scaffold destroy action returns status code 303 by t27duck · Pull Request #45383 · rails/rails
- が、このテンプレートはjbuilderが上書きしているので、jbuilderを有効にしているRailsアプリケーションでは結局302を返すコントローラが生成されてしまう…
- そしてオプションつけずにrails newするとjbuilderは入っている
- jbuilder側にPRはでている
- turbo-railsでは、PATCHやDELETEメソッドでリクエストするときにそれをPOSTと
ぼくらは結局どうしたらいいんですかね
- turbo-rails経由でPATCHやDELETEを発行しているぶんには気にせず302で問題なさそうではあるけど、気づかずにfetch APIを直接実行したときのことを考えるとサーバ側でも対応しておきたい
- Add
redirect_code_for_unsafe_http_methods
config by jonathanhefner · Pull Request #45393 · rails/rails 相当のものをモンキーパッチして、redirect_to時のステータスコードをデフォルト303に一律で変えてしまうのが楽そうかな〜と思っています