ルーティングのマッチングの優先順位のせいか期待通りのコントローラーで処理できないことがあります。そんなときにconstraintsオプションでroutesのパラメータのフォーマットを制限できます。たまーに使います。
たまーにしか使わなくて、なんで書いてあるんだっけ?と忘れていたので、思い出せた今回メモがてらに書いておきますよ。
例だよ
例えばこんな感じのroutes.rbになっているとします。
resources :messages, only: %i(index show)
namespace :messages do
resources :unreads, only: %i(index)
end
↑の例のようにnamespaceを切ると登場しうる書き方かなと思います。
で、3つのルーティングができます。
messages_path GET /messages(.:format) messages#index
message_path GET /messages/:id(.:format) messages#show
messages_unreads_path GET /messages/unreads(.:format) messages/unreads#index
1個めと2個めは割と問題ないのですが、3個目が曲者です。↑のルーティングの意図としてはhttp://localhost:3000/messages/unreadsなどとアクセスした場合にはunreads#index側にいってほしいはずです。
ですが、/messages/unreadsのunreadsの部分が、'/messages/:id’の:idの部分とマッチしてしまい、messages#show側で処理しようとしてしまいます。デフォルトでは:idの箇所は数値でも文字列でもなんでもいいことになっているので、unreadsという文字列のパラメータが渡ってきたとして判断しちゃうんですね。
こうするよ
これを想定通りに動かすためにconstraintsを使います。今回は:idの部分が数値である場合にmessages#showにいってほしいので、その条件を書きます。
resources :messages, only: %i(index show), constraints: {id: /\d+/} # <= この部分
namespace :messages do
resources :unreads, only: %i(index)
end
constraintsには正規表現でパターンを指定できます。今回は数値にマッチする場合、としました。これ以外の/messages/hogehogeは他で処理しますので、今回のルーティングだと/messages/数値と/messages/unreads以外はNo Routeになるわけですね。
constraintsについて詳しくは Rails のルーティング | Rails ガイド に記載があります。