ルーティングのマッチングの優先順位のせいか期待通りのコントローラーで処理できないことがあります。そんなときに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 ガイド に記載があります。