📖

【Rails】ルーティングでresourcesを使い、他のメソッドも追加するとき

2023/12/12に公開

要約

  • 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