📖
【Rails】ルーティングでresourcesを使い、他のメソッドも追加するとき
要約
- railsでresourcesメソッドを用い、各アクションのルーティングを定義し、それに加え独自のアクションを用意し、ルーティングに追記
- 独自のアクションのパスにPOSTしても、resourcesで定義したupdateアクションが実行されてしまう
- 独自アクションのパスがupdateアクションのパスに先にマッチしてしまったためで、独自アクションのルーティングをresourcesより先に定義すると解消した
バージョン
Rails7.0
Ruby3.2.2
やったこと
routes.rbにこのような記述をした
resources :orders
put 'orders/switch', to: 'orders#switch'
index.html.erb内にこのようなフォームを作った
<%= form_with url: orders_switch_path, method: :put do |f| %>
<%= f.button("切り替える") %>
<% end %>
そして、ordersコントローラーにswitchメソッドを用意
class OrdersController < ApplicationController
def switch
# ちょっとした更新を行い、indexにリダイレクト
end
end
発生した問題
この状態にしてindexのフォームでポストするとupdateが走ってしまう。
ルーティング、フォームのメソッドをpatchにしても同様だったが、postにするとswitchメソッドにいく。
原因と対処
このときのルーティングはこんな感じになっていました(関係ある部分のみ抜粋)。
order PATCH /orders/:id(.:format) orders#update
PUT /orders/:id(.:format) orders#update
orders_switch PUT /orders/switch(.:format) orders#switch
/orders/switchにポストしても、/orders/:idのルーティングとパスが一致してしまい、idがswitchのorderを探そうとしてエラーになっていました。
そのため、ルーティングに書く順序を逆にすると
put 'orders/switch', to: 'orders#switch' # こっちを先にする
resources :orders
先にorders/switchと一致するためswitchメソッドに行くようになりました。
orders_switch PUT /orders/switch(.:format) orders#switch
order PATCH /orders/:id(.:format) orders#update
PUT /orders/:id(.:format) orders#update
ですがそもそもresourcesを利用したrestfulなURL設計にswitchメソッドをねじ込んでいる点の微妙さは否めません。
Discussion