Ruby on Rails

【Rails】ルーティングの書き方まとめ

今回はルーティングでよく使う記法についてまとめていきたいと思います。
随時追記していきたいと思っていますので、これがないといったものがあればコメントいただけるとうれしいです。

resourcesとresource

まずは一番良く使うであろうresourcesから見ていきます。

resources

resourcesはデフォルトの7つのアクションを定義することができます。

resources :users
PrefixVerbURIController#Action
usersGET/usersusers#index
POST/usersusers#create
new_userGET/users/newusers#new
edit_userGET/users/:id/editusers#edit
userGET/users/:idusers#show
PATCH/users/:idusers#update
PUT/users/:idusers#update
DELETE/users/:idusers#destroy

もぐくん
もぐくん
よく書くやつだね!

resource

resourceはindexを除いた6つのアクションを定義します。resourcesとは違ってidが付きません。なので、1対1の関係のアソシエーションの際によく使われます。

例えば、usersテーブルとaddressesテーブルの関係が挙げられます。ここではユーザは一つの住所のみを持っていることとします。なので、1対1の関係です。この場合、URLとしては/users/:id/addressとしたいでしょう。その場合に登場するのが、resourceです。

resources :users do
  resource :address
end
PrefixVerbURIController#Action
user_addressPOST/users/:user_id/addressaddresses#create
new_user_addressGET/users/:user_id/address/newaddresses#new
edit_user_addressGET/users/:user_id/address/editaddresses#edit
user_addressGET/users/:user_id/addressaddresses#show
PATCH/users/:user_id/addressaddresses#update
PUT/users/:user_id/addressaddresses#update
DELETE/users/:user_id/addressaddresses#destroy
もぐくん
もぐくん
ほんとだ!
IDが入ってないね

名前空間について

名前空間を作るのにscopenamespacemoduleが使われます。それぞれ特徴があるので、それらを詳しく見ていきたいと思います。

scope

以下の場合に、scopeを使います。

  • URLを指定のパスにする
  • ファイル構成の変更はなし
scope 'v1' do
  resources :posts
end
PrefixVerbURIController#Action
postsGET/v1/postsposts#index
POST/v1/postsposts#create
new_postGET/v1/posts/newposts#new
edit_postGET/v1/posts/:id/editposts#edit
postGET/v1/posts/:idposts#show
PATCH/v1/posts/:idposts#update
PUT/v1/posts/:idposts#update
DELETE/v1/posts/:idposts#destroy

ファイル構成

namespace

以下の場合に、namespaceを使います。

  • URLを指定のパスにする
  • ファイル構成の変更あり
namespace 'v1' do
  resources :posts
end
PrefixVerbURIController#Action
v1_postsGET/v1/postsv1/posts#index
POST/v1/postsv1/posts#create
new_v1_postGET/v1/posts/newv1/posts#new
edit_v1_postGET/v1/posts/:id/editv1/posts#edit
v1_postGET/v1/posts/:idv1/posts#show
PATCH/v1/posts/:idv1/posts#update
PUT/v1/posts/:idv1/posts#update
DELETE/v1/posts/:idv1/posts#destroy

ファイル構成とコントローラー

ファイル構成は以下のようになり、ビューのファイル構成も変更になるので注意です。

また、コントローラーのクラス名に接頭辞がつきます。一般的に、ファイル構成に階層がある場合には、コントローラー名に名前空間をつける必要があります。

class V1::PostsController < ApplicationController
  # 略
end

module

以下の場合に、moduleを使います。

  • URLの変更なし
  • ファイル構成の変更あり
PrefixVerbURIController#Action
postsGET/postsv1/posts#index
POST/postsv1/posts#create
new_postGET/posts/newv1/posts#new
edit_postGET/posts/:id/editv1/posts#edit
postGET/posts/:idv1/posts#show
PATCH/posts/:idv1/posts#update
PUT/posts/:idv1/posts#update
DELETE/posts/:idv1/posts#destroy

ファイル構成とコントローラー

namespaceと同様にコントローラーとビューのファイル構成が変更になります。

こちらもファイル構成に階層があるので、コントローラーのクラス名にその接頭辞がつきます。

class V1::PostsController < ApplicationController
  # 略
end

もぐくん
もぐくん
ファイル構成が変更になるときはコントローラーに接頭辞がつくって覚えとけばいいね!

collectionとmember

collectionmemberindexcreateアクションなどのデフォルトのアクション以外を定義するのに使います。それぞれを詳しく見ていきます。

collection

チケット一覧から新着チケットの昇順に並べるユースケースを考えます。その場合、GET /tickets/new_arrivalを期待します。そうしたい場合、collectionを使用します。

resources :tickets do
  collection do
    get 'new_arrival'
    get 'trend'
    get 'near'
    get 'on_sale'
  end
end
PrefixVerbURIController#Action
new_arrival_ticketsGET/tickets/new_arrivalcomments#new_arrival
trend_ticketsGET/tickets/trendcomments#trend
near_ticketsGET/tickets/nearcomments#near
on_sale_ticketsGET/tickets/on_salecomments#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
PrefixVerbURIController#Action
purchase_ticketsGET/tickets/:id/purchasecomments#purchase

こうして、purchaseアクションを作成することができます。

def purchase
  ticket = Ticket.find(params[:id])
  # 略
end

もぐくん
もぐくん
tickets/の後に:idをつけるかつけないかの違いだね!

membercollectiononオプションを使って書くこともできます。

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'
PrefixVerbURIController#Action
sign_upGET/sign_upusers/registrations#new
loginGET/loginusers/sessions#new
logoutDELETE/logoutusers/sessions#destroy

また、下記のように書くこともできます。

get '/login' => 'users/sessions#new'
delete 'logout' => 'users/sessions#destroy'
get 'sign_up' => 'users/registrations#new'

ネストさせる場合のパスについて

ここでは、投稿に対してコメントを投稿できる機能を考えます。ふつうにルーティングを書くと以下のようになるかと思います。

resources :posts do
  resources :comments
end
PrefixVerbURIController#Action
post_commentsGET/posts/:post_id/commentscomments#index
POST/posts/:post_id/commentscomments#create
new_post_commentGET/posts/:post_id/comments/newcomments#new
edit_post_commentGET/posts/:post_id/comments/:id/editcomments#edit
post_commentGET/posts/:post_id/comments/:idcomments#show
PATCH/posts/:post_id/comments/:idcomments#update
PUT/posts/:post_id/comments/:idcomments#update
DELETE/posts/:post_id/comments/:idcomments#destroy

これでもいいのですが、ここで一つ考えてみます。ここでは、全てのコメントを表示しても仕方がないので、投稿についたコメントのみを表示したいとします。そうすると、/posts/:post_id/commentsは妥当であると言えます。しかし、コメントの編集や更新、削除をする際、post_idは必要でしょうか。どのコメントなのかを指定できれば問題ないので、/comments/:id/edit/comments/:idのほうがシンプルでよい設計といえます。そういう場合に使うのがshallowオプションです。

resources :posts, shallow: true do
  resources :comments
end
PrefixVerbURIController#Action
post_commentsGET/posts/:post_id/commentscomments#index
POST/posts/:post_id/commentscomments#create
new_post_commentGET/posts/:post_id/comments/newcomments#new
edit_commentGET/comments/:id/editcomments#edit
commentGET/comments/:idcomments#show
PATCH/comments/:idcomments#update
PUT/comments/:idcomments#update
DELETE/comments/:idcomments#destroy

shallowオプションをつけることでindex、create、new以外のアクションのパスから/posts/:idが消えています。理由は先程説明したとおりです。

さいごに

使いそうなルーティングでの記載方法についてかんたんにまとめました。こういうのよく使うというのがあればぜひコメントいただけるとうれしいです。
ここまで読んでいただき、ありがとうございました。

ABOUT ME
sakai
東京在住の30歳。元々は車部品メーカーで働いていてましたが、プログラミングに興味を持ちスクールに通ってエンジニアになりました。 そこからベンチャー → メガベンチャー → 個人事業主になりました。 最近は生成 AI 関連の業務を中心にやっています。 ヒカルチャンネル(Youtube)とワンピースが大好きです!