はじめに
今回は公式ドキュメントをもとにコメントなどを入れながら、railsルーティングをまとめてみたいと思います。
基本的な書き方
config/routes.rb はRailsアプリケーションで使用されるルーティングに関する情報を含むファイルです。
このファイルにルートを定義することで、アプリケーションのURLとコントローラーのアクションを関連付けることができます。
基本的なルーティングの書き方は以下のようになります。
get '/users/:id', to: 'users#show', as: 'user'
get 'profile', action: :show, controller: 'users'
resourceとresources
先ほど基本的なルーティングの書き方を示しましたが、実はそこまで使う機会は多くありません。
どちらかといえばこれから紹介する方法で書くことが多いので、ぜひそちらの書き方を押さえましょう。
resource :user
HTTP verb | パス | コントローラ#アクション | 目的 |
---|---|---|---|
GET | /users/new | users#new | ユーザー作成用のHTMLフォームを返す |
POST | /users | users#create | ユーザーを作成する |
GET | /users/:id | users#show | 1つしかないuserリソースを表示する |
GET | /users/:id/edit | users#edit | ユーザー編集用のHTMLフォームを返す |
PATCH/PUT | /users/:id | users#update | 1つしかないuserリソースを更新する |
DELETE | /users/:id | users#destroy | userリソースを削除する |
resrouces :users
HTTP verb | パス | コントローラ#アクション | 目的 |
---|---|---|---|
GET | /users | users#index | すべてのユーザーの一覧を表示 |
GET | /users/new | users#new | ユーザーを1つ作成するためのHTMLフォームを返す |
POST | /users | users#create | ユーザーを1つ作成する |
GET | /users/:id | users#show | 特定のユーザーを表示する |
GET | /users/:id/edit | users#edit | ユーザー編集用のHTMLフォームを1つ返す |
PATCH/PUT | /users/:id | users#update | 特定のユーザーを更新する |
DELETE | /users/:id | users#destroy | 特定のユーザーを削除する |
これらの大きな違いは2つあります。
1、resourceはindexアクションを作成しない
2、resourceは:idを作成しない
以上から、以下のような使い分けになります。
複数のリソース=>resources
単一のリソース=>resource
resourceは例えばログインしている場合などがそうですね。
わざわざidを取得する必要がないので、その場合はresourceとなります。
namespace
namespaceメソッドは、Railsのルーティングシステムで、特定のコントローラーやビューに名前空間を設定するために使用されます。名前空間は、関連するコントローラー、ビュー、およびヘルパーをグループ化することができます。
要は、プレフィックスをつけられるということです。
admin画面などが多い気がしますが、例えば以下のように書くと
resource :usersで作成したroutesの頭にadminがつきます。
namespace :admin do
resources :users
end
HTTP verb | パス | コントローラ#アクション | 名前付きルーティングヘルパー |
---|---|---|---|
GET | /admint/users | admin/users#index | admin_users_path |
GET | /admin/users/new | adming/users#new | new_admin_user |
POST | /admin/users | admin/users#create | admin_users_path |
GET | /admin/users/:id | admin/users#show | admin_user_path(:id) |
GET | /admin/users/:id/edit | admin/users#edit | edit_admin_user_path(:id) |
PATCH/PUT | /admin/users/:id | admin/users#update | admin_user_path(:id) |
DELETE | /admin/users/:id | admin/users#destroy | admin_user_path(:id) |
公式ドキュメントは以下のように補足が書かれています。
例外的に、(/adminが前についていない) /articlesをAdmin::ArticlesControllerにルーティングしたい場合は、以下のようにすることもできます。
scope module: 'admin' do
resources :articles, :comments
end
以下のようにブロックを使わない記述も可能です。
resources :articles, module: 'admin'
逆に、/admin/articlesを (Admin::なしの) ArticlesControllerにルーティングしたい場合は、以下のようにscopeブロックでパスを指定できます。
scope '/admin' do
resources :articles, :comments
end
以下のように単数形ルーティングでもできます。
resources :articles, path: '/admin/articles'
ルーティングのネスト
ルーティングはこれまでのような書き方だと対応できない場合が出てきます。
例えば、「書籍にコメントをする」みたいな機能がある場合、様々な書籍に様々なコメントがあるわけです。
「ある本のあるコメントを表示したいな」と考えた時には、これまでのルーティングでは対応できません。そんな時にルーティングをネストさせる必要があります。
resources :books do
resources :comments
end
このように書いた場合、以下のようにルーティングが生成されます。
Prefix Verb URI Pattern Controller#Action
book_comments GET /books/:book_id/comments(.:format) comments#index
POST /books/:book_id/comments(.:format) comments#create
new_book_comment GET /books/:book_id/comments/new(.:format) comments#new
edit_book_comment GET /books/:book_id/comments/:id/edit(.:format) comments#edit
book_comment GET /books/:book_id/comments/:id(.:format) comments#show
PATCH /books/:book_id/comments/:id(.:format) comments#update
PUT /books/:book_id/comments/:id(.:format) comments#update
DELETE /books/:book_id/comments/:id(.:format) comments#destroy
このように生成すると、例えば書籍とコメントのどちらもidがついているので、
それぞれのidを指定することで、特定の書籍に対する特定のコメントを表示できるわけですね。
/books/:book_id/comments/:id
ただし、注意点としてネストさせると複雑になるため、多くても1回が良いです。
それ以上する場合は、index/new/createのようなidを持たないもの(コレクション)のアクションだけを親のスコープの下で生成するという手法があります。
resources :books do
resources :comments, only: [:index, :new, :create]
end
resources :comments, only: [:show, :edit, :update, :destroy]
これは、shallowオプションを書くことで浅いネストを実現できます。(結果は上と同じです。)
resources :articles do
resources :comments, shallow: true
end
また、shallowをブロックで書くこともできます。
shallow do
resources :books do
resources :comments
resources :quotes
resources :drafts
end
end
どのような出力をしたいのかに応じて使い分けていきましょう。
ルーティングのconcern機能
concernを使うことで、他のリソースやルーティング内で使い回せる共通のルーティングを宣言できます。
これは、まあ使っても使わなくてもいい気がします。こんなものもあるんだなという認識で良いと思います。
concern :commentable do
resources :comments
end
concern :image_attachable do
resources :images, only: :index
end
concernを利用すると、同じようなルーティングを繰り返し記述せずに済み、
複数のルーティング間で同じ振る舞いを共有できます。
resources :messages, concerns: :commentable
resources :articles, concerns: [:commentable, :image_attachable]
上のコードは以下と同等です。(個人的にはこっちの方がわかりやすい、、、)
resources :messages do
resources :comments
end
resources :articles do
resources :comments
resources :images, only: :index
end
複数形のconcerns呼び出しはルーティング内のどの場所にでも配置できます。scopeやnamespaceブロックでは以下のように利用できます。
namespace :articles do
concerns :commentable
end
memberとcollection
他にもルーティングをさらにカスタマイズしたい場合にmemberやcollectionがあります。
どちらも似たような使い方ですが、idを付与するかどうかに大きな違いがあります。
結論から伝えると以下の通りです。
member=>idを付与する
collection=>idを付与しない
まあ名前の通り、memberは1人、2人のようなイメージなのでidがつくという感じですかね。
member
resources :users do
member do
get 'hoge'
end
end
上記のように member を使用すると以下のようにルーティングが設定されます。
/usersにidとhogeが乗っている(on)感じですね。
/users/:id/hoge
アクションが1つだけの場合は、以下のように書きます。
resources :users do
get 'hoge', on: :member
end
collection
resources :users do
collection do
get 'hoge'
end
end
上記のようにcollection を使用すると以下のようなルーティングが設定されます。
/usersにhogeが乗っている(on)感じですね。
/users/hoge
こちらもアクションが1つだけの場合は、以下のように書きます。
resources :users do
get 'hoge', on: :collection
end
7つのルーティングやネストだと対応できないなとなった時に使用を検討してみましょう。
名前付きルーティング :as
:asオプションを使うと、任意のルーティングに名前を指定できます。
名前付きルーティングを使用すると、以下のようなメリットがあります。
- コードの可読性が向上する
- URLの変更にも柔軟に対応できる
例えば、以下のようなルーティングがあるとします。
get '/books/:id', to: 'books#show'
このルーティングは、/books/:id というURLにGETリクエストが送信された場合、BooksControllerの showアクションが呼び出されます。
名前付きルーティングを使用すると、以下のように書くことができます。
get '/books/:id', to: 'books#show', as: :book
このルーティングでは、:book という名前が付けられています。
これにより、ルートを参照するための短いエイリアスが作成されます。
例えば、ビューから book_path(@book) というメソッドを呼び出すことで、/books/:id というURLにアクセスできます。
ルートが複雑である場合や、複数のビューやコントローラーで同じルートを参照する場合は、名前付きルートを積極的に使用することをおすすめします。
既存のルーティングを表示する
--expanded
--expandedオプションを使うと以下のように表示できるらしい。めっちゃ見やすい...
でもrailsのバージョンによっては使用できないみたいです...(少なくともRails 5.2.3では使用できませんでした。)
--[ Route 1 ]----------------------------------------------------
Prefix | users
Verb | GET
URI | /users(.:format)
Controller#Action | users#index
--[ Route 2 ]----------------------------------------------------
Prefix |
Verb | POST
URI | /users(.:format)
Controller#Action | users#create
-g
これはgrepオプションですね。多くの人が使っていると思います。
以下を実行するとURLヘルパー名、HTTP verb、URLパスのいずれかに部分マッチするルーティングが出力されます。
rails routes -g users
以下のようにもかけますが、-gの方がいいですね。
rails routes | grep users
-c
特定のコントローラに対応するルーティングだけを表示したい場合は、-cオプションを使います。
-gオプションだと、URLヘルパー名、HTTP verb、URLパスのいずれかに部分マッチするルーティングを出力するので、controllerに含まれているルーティングだけ知りたい場合は-cをつけると良いです。
まとめ
以上がrailsルーティングのまとめになります。
個人的にあんまり使わないなという部分は飛ばしたりしているので、より詳しく知りたい方は公式ドキュメントを参照してみると良いと思います。