はじめに
こんにちは。kosukein38です。
「こんな感じのpathにしたいんだけど、このルーティングっってどう書くんだっけ?」ってなって試行錯誤することが多かったので、ノート的によく使うルーティング記法をまとめました。
対象者
- Railsのルーティング設定に慣れていない方
ルーティングとは
Railsガイドによると、以下の定義。
Railsのルーターは受け取ったURLを認識し、適切なコントローラ内アクションやRackアプリケーションに振り分けます。ルーターはパスやURLも生成できるので、ビューでこれらのパスやURLを直接ハードコードする必要はありません。
ざっくりとは、クライアントから受け取ったHTTPリクエストを適切なコントローラーに振り分けたり、パスやURLを簡単に生成できるようにするためのルールです。HTTPリクエストを正しいコントローラーで処理し、適切なビューを表示させたり、APIでデータを返却したりしています。
よく使うルーティング
resourcesを使ったルーティング設定
:id
を含むリソース作られる。
(例)TaskモデルのCRUD
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
tasks_path | GET | /tasks(.:format) | tasks#index |
POST | /tasks(.:format) | tasks#create | |
new_task_path | GET | /tasks/new(.:format) | tasks#new |
edit_task_path | GET | /tasks/:id/edit(.:format) | tasks#edit |
task_path | GET | /tasks/:id(.:format) | tasks#show |
PATCH(PUT) | /tasks/:id(.:format) | tasks#update | |
DELETE | /tasks/:id(.:format) | tasks#destroy |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
resources :tasks
end
resourceを使ったルーティング設定
:id
を含むルーティングが生成されません。
(例)SettingモデルのCRUD
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
new_settings_path | GET | /settings/new(.:format) | settings#new |
edit_settings_path | GET | /settings/edit(.:format) | settings#edit |
settings_path | GET | /settings(.:format) | settings#show |
PATCH(PUT) | /settings(.:format) | settings#update | |
DELETE | /settings(.:format) | settings#destroy | |
POST | /settings(.:format) | settings#create |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
resource :settings
end
名前空間を使ったルーティング設定
adminと他のリソースを分けたい時などに使います。
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
admin_tasks_path | GET | /admin/tasks(.:format) | admin/tasks#index |
POST | /admin/tasks(.:format) | admin/tasks#create | |
new_admin_task_path | GET | /admin/tasks/new(.:format) | admin/tasks#new |
edit_admin_task_path | GET | /admin/tasks/:id/edit(.:format) | admin/tasks#edit |
admin_task_path | GET | /admin/tasks/:id(.:format) | admin/tasks#show |
PATCH(PUT) | /admin/tasks/:id(.:format) | admin/tasks#update | |
DELETE | /admin/tasks/:id(.:format) | admin/tasks#destroy |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
namespace :admin do
resources :tasks
end
end
また、以下のようにすると、できるpathは上と同様にadmin配下(admin/~~
)となりますが、コントローラーはadmin配下ではなく、app/controllers/tasks_contraller.rb
を参照します
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
namespace :admin do
resources :tasks
end
end
ネストしたルーティング設定
ネストは1回までが原則。
(例)1対多でtaskにcommentsが紐づいている場合
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
task_comments_path | GET | /tasks/:task_id/comments(.:format) | comments#index |
POST | /tasks/:task_id/comments(.:format) | comments#create | |
new_task_comment_path | GET | /tasks/:task_id/comments/new(.:format) | comments#new |
edit_task_comment_path | GET | /tasks/:task_id/comments/:id/edit(.:format) | comments#edit |
task_comment_path | GET | /tasks/:task_id/comments/:id(.:format) | comments#show |
PATCH(PUT) | /tasks/:task_id/comments/:id(.:format) | comments#update | |
DELETE | /tasks/:task_id/comments/:id(.:format) |
comments#destroy |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
resources :tasks do
resources :comments
end
end
ネストを浅くするshallowオプションを使ったルーティング設定
edit
, show
, update
, destroy
アクションのpathが浅くなります。
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
task_comments_path | GET | /tasks/:task_id/comments(.:format) | comments#index |
POST | /tasks/:task_id/comments(.:format) | comments#create | |
new_task_comment_path | GET | /tasks/:task_id/comments/new(.:format) | comments#new |
edit_task_comment_path | GET | /comments/:id/edit(.:format) | comments#edit |
task_comment_path | GET | /comments/:id(.:format) | comments#show |
PATCH(PUT) | /comments/:id(.:format) | comments#update | |
DELETE | /comments/:id(.:format) |
comments#destroy |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
shallow do
resources :tasks do
resources :comments
end
end
end
scope
メソッドに:shallow_path
オプションを使ったルーティング設定
指定されたパラメータをメンバーのパスの冒頭に追加します。
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
task_comments_path | GET | /tasks/:task_id/comments(.:format) | comments#index |
POST | /tasks/:task_id/comments(.:format) | comments#create | |
new_task_comment_path | GET | /tasks/:task_id/comments/new(.:format) | comments#new |
edit_comment_path | GET | /corporation/comments/:id/edit(.:format) | comments#edit |
comment_path | GET | /corporation/comments/:id(.:format) | comments#show |
PATCH(PUT) | /corporation/comments/:id(.:format) | comments#update | |
DELETE | /corporation/comments/:id(.:format) | comments#destroy |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
scope shallow_path: "corporation" do
resources :tasks do
resources :comments, shallow: true
end
end
end
scope
メソッドに:shallow_prefix
オプションを使ったルーティング設定
指定されたパラメータを(パスではなく)名前付きルーティングヘルパー名の冒頭に追加します。
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
task_comments_path | GET | /tasks/:task_id/comments(.:format) | comments#index |
POST | /tasks/:task_id/comments(.:format) | comments#create | |
new_task_comment_path | GET | /tasks/:task_id/comments/new(.:format) | comments#new |
edit_corporation_comment_path | GET | /comments/:id/edit(.:format) | comments#edit |
corporation_comment_path | GET | /comments/:id(.:format) | comments#show |
PATCH(PUT) | /comments/:id(.:format) | comments#update | |
DELETE | /comments/:id(.:format) | comments#destroy |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
scope shallow_prefix: "corporation" do
resources :tasks do
resources :comments, shallow: true
end
end
end
メンバールーティングを使ったルーティング設定
デフォルトの7つのアクションに加えて、別のRESTfulなアクションを追加したい場合に使用します。メンバールーティングは:id
を伴うルーティングに対して、アクションを追加したい場合に用います。
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
reset_password_password_path | GET | /passwords/:id/reset_password(.:format) | passwords#reset_password |
assign_password_path | GET | /passwords/:id/assign(.:format) | passwords#assign |
unassign_password_path | GET | /passwords/:id/unassign(.:format) | passwords#unassign |
passwords_path | GET | /passwords(.:format) | passwords#index |
POST | /passwords(.:format) | passwords#create | |
GET | /passwords/new(.:format) | passwords#new | |
GET | /passwords/:id/edit(.:format) | passwords#edit | |
GET | /passwords/:id(.:format) | passwords#show | |
PATCH(PUT) | /passwords/:id(.:format) | passwords#update | |
DELETE | /passwords/:id(.:format) | passwords#destroy |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
resources :passwords do
member do
post 'csv_import'
end
end
end
コレクションルーティングを使ったルーティング設定
メンバールーティング同様、デフォルトの7つのアクションに加えて、別のRESTfulなアクションを追加したい場合に使用しますが、:id
を伴わないルーティングに対して、アクションを追加したい場合に用います。
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
csv_import_passwords_path | POST | /passwords/csv_import(.:format) | passwords#csv_import |
passwords_path | GET | /passwords(.:format) | passwords#index |
POST | /passwords(.:format) | passwords#create | |
GET | /passwords/new(.:format) | passwords#new | |
GET | /passwords/:id/edit(.:format) | passwords#edit | |
GET | /passwords/:id(.:format) | passwords#show | |
PATCH(PUT) | /passwords/:id(.:format) | passwords#update | |
DELETE | /passwords/:id(.:format) | passwords#destroy |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
resources :passwords do
member do
post 'csv_import'
end
end
end
名前付きルーティング設定
:as
オプションを使うと、任意のルーティングに名前を指定できます。
【asつけない場合】
Helperが生成されません
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
GET | /stations/:station_id/access_guide(.:format) | stations#access_guide |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
get 'stations/:station_id/access_guide', to: 'stations#access_guide'
end
【asつけた場合】
Helperが生成されます。
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
station_access_guide_path | GET | /stations/:station_id/access_guide(.:format) | stations#access_guide |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
get 'stations/:station_id/access_guide', to: 'stations#access_guide', as: 'station_access_guide'
end
名前付きルーティングパラメータのオーバーライド
Railsガイドの説明が分かりやすいのでそのまま引用します。
:param
オプションは、デフォルトのリソース識別子:id
(ルーティングの生成に使われる動的なセグメントの名前) をオーバーライドします。params[<:パラメータ>]
を使って、コントローラからそのセグメントにアクセスできます。
【param: 'token'
があるとき】
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
reservations_path | POST | /reservations(.:format) | reservations#create |
reservation_path | PATCH(PUT) | /reservations/:token(.:format) | reservations#update |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
resources :reservations, only: [:create, :update], param: 'token'
end
【param: 'token'
がないとき】
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
reservations_path | POST | /reservations(.:format) | reservations#create |
reservation_path | PATCH(PUT) | /reservations/:id(.:format) | reservations#update |
上を設定する場合のルーティングの記法
Rails.application.routes.draw do
resources :reservations, only: [:create, :update]
end
ルーティングは探索順に注意!!
これまでの内容をふまえて、例えば以下のようなルーティングを考えてみます。
Rails.application.routes.draw do
resources :reservations, only: [:create, :edit, :update], param: 'token' do
member do
get '/:reservation_no', to: 'reservations#guest_page', as: 'guest_page'
end
end
一見良さそうにみえるのですが、生成されるパスは以下の順番になります。
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
guest_page_reservation_path | GET | /reservations/:token/:reservation_no(.:format) | reservations#guest_page |
reservations_path | POST | /reservations(.:format) | reservations#create |
edit_reservation_path | GET | /reservations/:token/edit(.:format) | reservations#edit |
reservation_path | PATCH(PUT) | /reservations/:token(.:format) | reservations#update |
実はこの書き方ではedit
アクションのpathにアクセスすると、先にguest_page
アクションのパスがヒットしてしまい、エラーが発生します。
これはguest_page
アクションのパスが:reservation_no
という動的なセグメントを含んでおり、 Railsがルーティングを探索する際に、このパスがedit
アクションのパスよりも先にヒットしてしまうためです。
なので、例えば以下のように修正します。
Rails.application.routes.draw do
get '/reservations/:token/edit', to: 'reservations#edit', as: 'edit_reservation'
resources :reservations, only: [:create, :update], param: 'token' do
member do
get '/:reservation_no', to: 'reservations#guest_page', as: 'guest_page'
end
end
end
そうすると生成されるパスは次のようになり、edit
アクションのパスが一番上に生成されるようになります。
Railsは上から順番にパスを検索するため、こうすることで正しいパスを認識するようになります。
(もっと上手い書き方があるかもしれません...)
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
edit_reservation_path | GET | /reservations/:token/edit(.:format) | reservations#edit |
guest_page_reservation_path | GET | /reservations/:token/:reservation_no(.:format) | reservations#guest_page |
reservations_path | POST | /reservations(.:format) | reservations#create |
reservation_path | PATCH(PUT) | /reservations/:token(.:format) | reservations#update |
resourcesで書いたルーティングが一番先に生成されるのかと思いきや、ブロックの中身のルーティングが先にできて、その後ろになるのは個人的に間違えやすいポイントでした。
(中のブロックを先に評価しているからかな?)
まとめ
- よく使うルーティング記法と、その例の出力結果をまとめました
- 動的なセグメント(
:id
みたいなやつ)を使う時は、他のルーティングに影響しないかをチェックする