今回はルーティングでよく使う記法についてまとめていきたいと思います。
随時追記していきたいと思っていますので、これがないといったものがあればコメントいただけるとうれしいです。
resourcesとresource
まずは一番良く使うであろうresourcesから見ていきます。
resources
resourcesはデフォルトの7つのアクションを定義することができます。
resources :users
Prefix | Verb | URI | Controller#Action |
users | GET | /users | users#index |
POST | /users | users#create | |
new_user | GET | /users/new | users#new |
edit_user | GET | /users/:id/edit | users#edit |
user | GET | /users/:id | users#show |
PATCH | /users/:id | users#update | |
PUT | /users/:id | users#update | |
DELETE | /users/:id | users#destroy |
resource
resourceはindexを除いた6つのアクションを定義します。resourcesとは違ってidが付きません。なので、1対1の関係のアソシエーションの際によく使われます。
例えば、usersテーブルとaddressesテーブルの関係が挙げられます。ここではユーザは一つの住所のみを持っていることとします。なので、1対1の関係です。この場合、URLとしては/users/:id/addressとしたいでしょう。その場合に登場するのが、resourceです。
resources :users do
resource :address
end
Prefix | Verb | URI | Controller#Action |
user_address | POST | /users/:user_id/address | addresses#create |
new_user_address | GET | /users/:user_id/address/new | addresses#new |
edit_user_address | GET | /users/:user_id/address/edit | addresses#edit |
user_address | GET | /users/:user_id/address | addresses#show |
PATCH | /users/:user_id/address | addresses#update | |
PUT | /users/:user_id/address | addresses#update | |
DELETE | /users/:user_id/address | addresses#destroy |
IDが入ってないね
名前空間について
名前空間を作るのにscope
やnamespace
、module
が使われます。それぞれ特徴があるので、それらを詳しく見ていきたいと思います。
scope
以下の場合に、scope
を使います。
- URLを指定のパスにする
- ファイル構成の変更はなし
scope 'v1' do
resources :posts
end
Prefix | Verb | URI | Controller#Action |
posts | GET | /v1/posts | posts#index |
POST | /v1/posts | posts#create | |
new_post | GET | /v1/posts/new | posts#new |
edit_post | GET | /v1/posts/:id/edit | posts#edit |
post | GET | /v1/posts/:id | posts#show |
PATCH | /v1/posts/:id | posts#update | |
PUT | /v1/posts/:id | posts#update | |
DELETE | /v1/posts/:id | posts#destroy |
ファイル構成
namespace
以下の場合に、namespace
を使います。
- URLを指定のパスにする
- ファイル構成の変更あり
namespace 'v1' do
resources :posts
end
Prefix | Verb | URI | Controller#Action |
v1_posts | GET | /v1/posts | v1/posts#index |
POST | /v1/posts | v1/posts#create | |
new_v1_post | GET | /v1/posts/new | v1/posts#new |
edit_v1_post | GET | /v1/posts/:id/edit | v1/posts#edit |
v1_post | GET | /v1/posts/:id | v1/posts#show |
PATCH | /v1/posts/:id | v1/posts#update | |
PUT | /v1/posts/:id | v1/posts#update | |
DELETE | /v1/posts/:id | v1/posts#destroy |
ファイル構成とコントローラー
ファイル構成は以下のようになり、ビューのファイル構成も変更になるので注意です。
また、コントローラーのクラス名に接頭辞がつきます。一般的に、ファイル構成に階層がある場合には、コントローラー名に名前空間をつける必要があります。
class V1::PostsController < ApplicationController
# 略
end
module
以下の場合に、module
を使います。
- URLの変更なし
- ファイル構成の変更あり
Prefix | Verb | URI | Controller#Action |
posts | GET | /posts | v1/posts#index |
POST | /posts | v1/posts#create | |
new_post | GET | /posts/new | v1/posts#new |
edit_post | GET | /posts/:id/edit | v1/posts#edit |
post | GET | /posts/:id | v1/posts#show |
PATCH | /posts/:id | v1/posts#update | |
PUT | /posts/:id | v1/posts#update | |
DELETE | /posts/:id | v1/posts#destroy |
ファイル構成とコントローラー
namespace
と同様にコントローラーとビューのファイル構成が変更になります。
こちらもファイル構成に階層があるので、コントローラーのクラス名にその接頭辞がつきます。
class V1::PostsController < ApplicationController
# 略
end
collectionとmember
collection
とmember
はindex
やcreate
アクションなどのデフォルトのアクション以外を定義するのに使います。それぞれを詳しく見ていきます。
collection
チケット一覧から新着チケットの昇順に並べるユースケースを考えます。その場合、GET /tickets/new_arrival
を期待します。そうしたい場合、collection
を使用します。
resources :tickets do
collection do
get 'new_arrival'
get 'trend'
get 'near'
get 'on_sale'
end
end
Prefix | Verb | URI | Controller#Action |
new_arrival_tickets | GET | /tickets/new_arrival | comments#new_arrival |
trend_tickets | GET | /tickets/trend | comments#trend |
near_tickets | GET | /tickets/near | comments#near |
on_sale_tickets | GET | /tickets/on_sale | comments#on_sale |
こうして、新しいアクションを定義できたので、コントローラーにアクションを追加することができます。
def new_arrival
@tickets = Ticket.all.new_arrival_order(params[:page])
render :index
end
少しはイメージを持ってもらえたかと思います。次はmember
について解説します。
member
今度はチケットを購入するアクションを作るユースケースを考えます。この場合、POST /tickets/:id/purchase
を期待します。なぜなら、購入するのはある一枚のチケットなので、先程の例と異なりどのチケットを購入するかを表す:id
が必要です。この場合、member
を使用します。
resources :posts do
member do
resources :comments
end
end
Prefix | Verb | URI | Controller#Action |
purchase_tickets | GET | /tickets/:id/purchase | comments#purchase |
こうして、purchase
アクションを作成することができます。
def purchase
ticket = Ticket.find(params[:id])
# 略
end
member
やcollection
はon
オプションを使って書くこともできます。
resources :tickets do
get 'new_arrival', on: :collection
get 'trend', on: :collection
get 'near', on: :collection
get 'on_sale', on: :collection
post 'purchase', on: :member
end
パス名を変更したい場合
新規登録のためのパスを/users/registrations/new
のようにコントローラー名をそのまま使うのではなく、/sign_up
にしたくなるかと思います。その場合、以下のようにルーティングを書きます。
get '/login', to: 'users/sessions#new'
delete 'logout', to: 'users/sessions#destroy'
get 'sign_up', to: 'users/registrations#new'
Prefix | Verb | URI | Controller#Action |
sign_up | GET | /sign_up | users/registrations#new |
login | GET | /login | users/sessions#new |
logout | DELETE | /logout | users/sessions#destroy |
また、下記のように書くこともできます。
get '/login' => 'users/sessions#new'
delete 'logout' => 'users/sessions#destroy'
get 'sign_up' => 'users/registrations#new'
ネストさせる場合のパスについて
ここでは、投稿に対してコメントを投稿できる機能を考えます。ふつうにルーティングを書くと以下のようになるかと思います。
resources :posts do
resources :comments
end
Prefix | Verb | URI | Controller#Action |
post_comments | GET | /posts/:post_id/comments | comments#index |
POST | /posts/:post_id/comments | comments#create | |
new_post_comment | GET | /posts/:post_id/comments/new | comments#new |
edit_post_comment | GET | /posts/:post_id/comments/:id/edit | comments#edit |
post_comment | GET | /posts/:post_id/comments/:id | comments#show |
PATCH | /posts/:post_id/comments/:id | comments#update | |
PUT | /posts/:post_id/comments/:id | comments#update | |
DELETE | /posts/:post_id/comments/:id | comments#destroy |
これでもいいのですが、ここで一つ考えてみます。ここでは、全てのコメントを表示しても仕方がないので、投稿についたコメントのみを表示したいとします。そうすると、/posts/:post_id/comments
は妥当であると言えます。しかし、コメントの編集や更新、削除をする際、post_idは必要でしょうか。どのコメントなのかを指定できれば問題ないので、/comments/:id/edit
や/comments/:id
のほうがシンプルでよい設計といえます。そういう場合に使うのがshallow
オプションです。
resources :posts, shallow: true do
resources :comments
end
Prefix | Verb | URI | Controller#Action |
post_comments | GET | /posts/:post_id/comments | comments#index |
POST | /posts/:post_id/comments | comments#create | |
new_post_comment | GET | /posts/:post_id/comments/new | comments#new |
edit_comment | GET | /comments/:id/edit | comments#edit |
comment | GET | /comments/:id | comments#show |
PATCH | /comments/:id | comments#update | |
PUT | /comments/:id | comments#update | |
DELETE | /comments/:id | comments#destroy |
shallow
オプションをつけることでindex、create、new
以外のアクションのパスから/posts/:id
が消えています。理由は先程説明したとおりです。
さいごに
使いそうなルーティングでの記載方法についてかんたんにまとめました。こういうのよく使うというのがあればぜひコメントいただけるとうれしいです。
ここまで読んでいただき、ありがとうございました。