おはようございます!
朝から警察の方に職務質問を受けてしまった、プレイライフの熊崎です。
そんな怪しさ全開の雰囲気が出ていた僕ですが、引き続きアウトプットを行なっていきたいと思います。
constraintsとは?
:constraintsオプションを使って、動的セグメントのURLフォーマットを特定の形式に制限できます。
ref: https://railsguides.jp/routing.html#セグメントを制限する
→ ルーティングに制限を設定するオプション。constraintsの和訳が制約なので、そのまんま。
制限の仕方
get '/articles/:id' , to: 'articles#show', constraints: { id: /[A-Z]\d{5}/ }
# match => /articles/A11111, not_match => /articles/111
また、リクエスト内容に応じて制限を加えることができる。
ref: https://railsguides.jp/routing.html#リクエスト内容に応じて制限を加える
get '/articles/:id' , to: 'articles#show', constraints: { port: 3000 }
# ポート番号が3000以外の場合、マッチしない。
また、以下のようにmatchesメソッドを使用して制限を加えることができる。
get '/articles/:id' , to: 'articles#show', constraints: ArticleIdRestrict.new
class ArticleIdRestrict
def matches?(request)
# URLの後ろについているidが、記事テーブルのidの中に含まれているか?
Article.pluck(:id).include?(request[:id])
end
end
どんな時に使用するのか?
→ ルーティングを制限したいとき。
例: 記事を、ジャンルで絞り込みを行う際。
genresテーブル
id | name |
---|---|
1 | SQL |
2 | Rails |
get '/articles/:genre_name', to: 'articles#index', constraints: ArticleGenreRestrict.new
class ArticleGenreRestrict
def matches?(request)
# ジャンル名がSQLかRailsの場合のみマッチする。
Genre.pluck(:name).include?(request[:genre_name])
end
end
メリット
- コントローラー側で、クエリパラメータが正しいかどうかを判断する必要がなくなる。
注意点
- 以下のように書くと、指定したルーティングが無効になる。
resources :articles, only: %i[index]
get '/articles/:genre_name', to: 'articles#index', constraints: ArticleGenreRestrict.new
class ArticleGenreRestrict
def matches?(request)
# ジャンル名がSQLかRailsの場合のみマッチする。
Genre.pluck(:name).include?(request[:genre_name])
end
end
理由
Railsのルーティングは、ルーティングファイルの「上からの記載順に」マッチします。このため、たとえばresources :photosというルーティングがget 'photos/poll'よりも前の行にあれば、resources行のshowアクションがget行の記述よりも優先されますので、get行のルーティングは有効になりません。これを修正するには、get行をresources行 よりも上 の行に移動してください。これにより、get行がマッチするようになります。
ref: https://railsguides.jp/routing.html#crud、動詞、アクション
参考記事
https://railsguides.jp/routing.html#セグメントを制限する
https://railsguides.jp/routing.html#リクエスト内容に応じて制限を加える
https://railsguides.jp/routing.html#crud、動詞、アクション
最後に
ルーティング周りでこんな機能があるとは思わなかった。
まだまだ知らない機能がいっぱいあるので、1つ1つ覚えていく必要があると感じた。