Railsのルーティングファイル(routes.rb)の中でresourcesという記述をよく見かけることがあります。
これは、DB操作でよく使う、複数のルーティングをまとめて作成してくれる便利な記述です。
この、resourcesの意味や使い方を解説しています。
resourcesとは?
resourcesとはリソーシズと読み、DB操作に必要な複数のルーティングを一度に生成してくれるものです。
使い方はresoucesの後にコントローラ名を指定します。
※コントローラ名は小文字で指定します。単語が連結している場合はスネークケースで記述します(コントローラのファイル名に合わせます)
resources :コントローラ名
resourcesで生成されるルート
resourcesを指定すると、次の8個のルートをまとめて生成します。
アクション | HTTP動詞 | パス | 内容 |
---|---|---|---|
index | GET | /コントローラ名 | 一覧を表示 |
create | POST | /コントローラ名 | データ追加処理 |
new | GET | /コントローラ名/new | データ追加用の画面 |
edit | GET | /コントローラ名/:id/edit | 指定したデータを変更する画面 |
show | GET | /コントローラ名/:id | 指定したデータの詳細画面 |
update | PATCH | /コントローラ名/:id | 指定したデータの更新処理(変更箇所のみ) |
update | PUT | /コントローラ名/:id | 指定したデータの更新処理(全体を更新) |
destroy | DELETE | /コントローラ名/:id | 指定したデータの削除処理 |
GETメソッドはWEB上に画面を表示するリクエストです。それ以外の処理はデータを送信したり、DBと通信するメソッドです。
ルーティングの対比
ルーティングに記述するresourcesをreosurcesを使わずに書くこともできます。以下のルーティングはいずれも同じ処理になります。
Rails.application.routes.draw do
resources :articles
end
↓↑ 同じ
Rails.application.routes.draw do
get 'articles', to: 'articles#index'
get 'articles/:id', to: 'articles#show'
get 'articles/new'
post 'articles', to: 'articles#create'
get 'articles/:id/edit', to: 'articles#edit'
patch 'articles/:id', to: 'articles#update'
delete 'articles/:id', to: 'articles#destroy'
end
reousrcesの実例
Usersコントローラを生成し、ルーティングにresourcesを記述したあとに、ルーティングの一覧を表示してみます。
コントローラの生成
rails g controller <コントローラ名>
で Usersコントローラを作成します。アクションはresourcesで追加するので、ここではコントローラ名のみ指定します。
# rails g controller Users
Running via Spring preloader in process 370
create app/controllers/users_controller.rb
get 'users/show'
invoke erb
create app/views/users
invoke test_unit
create test/controllers/users_controller_test.rb
invoke helper
create app/helpers/users_helper.rb
invoke test_unit
invoke assets
invoke scss
create app/assets/stylesheets/users.scss
コントローラの詳細については下記をご参考ください。
ルーティングの作成
続いてルーティングを作成します。シンプルにresources :users
を追記するだけです。
Rails.application.routes.draw do
resources :users
end
ルートの確認
rails g routes
コマンドでルートの一覧を表示させます。
8つのルートが自動で生成されていることがわかります。
# rails routes
Prefix Verb URI Pattern Controller#Action
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
生成するルートを制限する
resourcesを使うと8つのルートが生成されますが、これらのうち一部のみあればいいという場合があります。
そんなときのために便利な2つのオプションが用意されています。
- only (指定したアクションのみ)
- exept(指定したアクション以外)
only (指定したアクションのみ)
onlyオプションを使うと、指定したアクションに対応するルートのみを作成することができます。
複数指定する場合は、カンマでつなぎます。
resources :コントローラ名, only: [:アクション名1, :アクション名2,,,]
実例
index、showアクションに対応するルーティングのみ作成したい場合は次のようになります。
Rails.application.routes.draw do
resources :users, only: [:index, :show]
end
ルートの確認
rails g routes
コマンドでルートの一覧を表示させます。
指定したindexとshowの2つのルートが自動で生成されていることがわかります。
# rails routes
Prefix Verb URI Pattern Controller#Action
users GET /users(.:format) users#index
user GET /users/:id(.:format) users#show
(補足)一つのルートのみを表示させたいときは、配列にせず直接指定することもできます。最初は一覧ページしか用意せず、今後ルーティングを増やしていきたい場合に使えます。
#1つのアクションに対応するルート
resources :users, only: :index
#以下と同じ
get 'users/index'
exept(指定したアクション以外)
exceptオプションを使うと、指定したアクションに以外に対応するルートのみを作成することができます。
複数指定する場合は、カンマでつなぎます。
resources :コントローラ名, except: [:アクション名1, :アクション名2,,,]
実例
index、showアクションに対応するルーティングのみ作成したい場合は、それ以外のすべてのアクションを指定します。
Rails.application.routes.draw do
resources :users, except: [:new, :create, :edit, :update, :destroy]
end
ルートの確認
rails g routes
コマンドでルートの一覧を表示させます。
指定したindexとshowの2つのルートが自動で生成されていることがわかります。
# rails routes
Prefix Verb URI Pattern Controller#Action
users GET /users(.:format) users#index
user GET /users/:id(.:format) users#show
resource
詳細ページが不要で、一覧ページの中でデータ追加や変更のみを行う場合に、indexアクションに対応するルートと、id無しのパスを生成するreosourceメソッドも用意されています。(※単数形)
resource :アクション名
とすると、indexアクションに対応するルートおよび、id付きのルートを生成しません。
アクション | HTTP動詞 | パス | 内容 |
---|---|---|---|
create | POST | /コントローラ名 | データ追加処理 |
new | GET | /コントローラ名/new | データ追加用の画面 |
edit | GET | /コントローラ名/edit | データを変更する画面 |
show | GET | /コントローラ名 | データを表示する画面 |
update | PATCH | /コントローラ名/:id | データの更新処理(変更箇所のみ) |
update | PUT | /コントローラ名/:id | データの更新処理(全体を更新) |
destroy | DELETE | /コントローラ名/:id | データの削除処理 |
# rails routes
Prefix Verb URI Pattern Controller#Action
new_user GET /users/new(.:format) users#new
edit_user GET /users/edit(.:format) users#edit
users GET /users/(.:format) users#show
PATCH /users/(.:format) users#update
PUT /users/(.:format) users#update
DELETE /users/(.:format) users#destroy
POST /users(.:format) users#create
showアクションに対応するprefixはusersになります。(resourcesの場合はuser)
resourcesと同じく、onlyやexceptオプションが使えます。
複数のresourcesをまとめて記述する
resourcesは複数のコントローラを1行で記述することができます。
resource :コントローラ名1, :コントローラ名2, :コントローラ名3,,,,
例えば、Usersコントローラと、ClientNamesコントローラを指定する場合は次のようになります。
resource :users, :client_names
これは以下と同じ指定になります。
resource :users
resource :client_names
オプションの適用
resourcesに複数のコントローラ名を指定した場合も、onlyとexceptを適用することもできます。
その場合は、一行に記述したそれぞれのコントローラに同じオプションが適用されます。
resources :users, :client_names, only: [:index, :show]
これは以下と同じ指定になります。
resource :users, only: [:index, :show]
resource :client_names, only: [:index, :show]
名前空間(namespace)を指定する
通常の状態だと、app > controllers 直下にコントローラファイルを作成します。ですが、機能やサービス毎にコントローラファイルやルートをまとめたい場合、その下にディレクトリを作成することがあります。
例えば、app > controllers > article として、記事に関連するコントローラはこのarticlesディレクトリに入れる場合です。
このとき、名前空間(namespace)を使うことでルーティングやアクションを簡単に記述することができます。
いつ使うか?
このnamespaceの具体的な使いどころとしては、例えば、ブログ(blog)とニュース(news)など複数のユーザー投稿型のサービスを持つ場合に、DB操作ができるパスを、以下のように作成するときに便利です。
https://example.com/blog/~
https://example.com/news/~
ルーティングファイルの書き方
書き方はとてもシンプルで、namespace の後ろに :ディレクトリ名 を記述して、ブロックの中にresourcesを指定します。
namespace :ディレクトリ名 do
resources :コントローラ名
end
resourcesは複数指定することもできます。
記述したすべてのresourcesにnamespaceで指定したディレクトリ名が追加されます。
namespace :ディレクトリ名 do
resources :コントローラ名1, :コントローラ名2, :コントローラ名3,,,
end
対応するコントローラ
namespaceを使う場合は、コントローラクラスの名前空間も同様の構造になっている必要があります。
クラスに名前空間を指定するには、クラス名の前に 名前空間::
をつけます。
例えば、articleディレクトリ配下に作った、articlesコントローラに対応するコントローラクラス名はArticle::ArticlesController
となります。
class Article::ArticlesController < ApplicationController
(省略)
end
生成されるルート
生成されるルートは、通常のresourcesで生成されるコントローラ名の上に、指定したディレクトリ名が記述されたものになります。
prefix | HTTP動詞 | Path | Controller#Action |
---|---|---|---|
ディレクトリ名_コントローラ名 | GET | /ディレクトリ名/コントローラ名 (.:format) | ディレクトリ名/コントローラ名#index |
POST | /ディレクトリ名/コントローラ名(.:format) | ディレクトリ名/コントローラ名#create | |
new_ディレクトリ名_コントローラ名 | GET | /ディレクトリ名/コントローラ名new(.:format) | ディレクトリ名/コントローラ名#new |
edit_ディレクトリ名_コントローラ名 | GET | /ディレクトリ名/コントローラ名:id/edit(.:format) | ディレクトリ名/コントローラ名#edit |
ディレクトリ名_コントローラ名 | GET | /ディレクトリ名/コントローラ名:id(.:format) | ディレクトリ名/コントローラ名#show |
PATCH | /ディレクトリ名/コントローラ名:id(.:format) | ディレクトリ名/コントローラ名#update | |
PUT | /ディレクトリ名/コントローラ名:id(.:format) | ディレクトリ名/コントローラ名#update | |
DELETE | /ディレクトリ名/コントローラ名:id(.:format) | ディレクトリ名/コントローラ名#destroy |
名前空間(namespace)の使用実例
記事投稿ができるarticleディレクトリを作成して、その中に、articles_controllerを作成し、ルーティングを行う場合は以下のようになります。
コントローラの作成
コントローラはarticleディレクトリ配下に作成するので、コントローラ名は article/articles とします。(※コントローラ名は基本的に複数形を指定します)
# rails g controller article/articles
Running via Spring preloader in process 250
create app/controllers/article/articles_controller.rb
invoke erb
create app/views/article/articles
invoke test_unit
create test/controllers/article/articles_controller_test.rb
invoke helper
create app/helpers/article/articles_helper.rb
invoke test_unit
invoke assets
invoke scss
create app/assets/stylesheets/article/articles.scss
controllers > article > articles_controller.rb を作成できました。
なお、コントローラファイルのクラス名は、ディレクトリ構造に合わせた名前空間がついています。(便利です)
class Article::ArticlesController < ApplicationController
(省略)
end
ルーティングの作成
続いて対応するルーティングを作成します。
Rails.application.routes.draw do
namespace :article do
resources :articles
end
end
ルーティングが正しく設定されているか、rails routes
コマンドで確かめます。
root@e1c25463cf4f:/rails-test# rails routes
Prefix Verb URI Pattern
Controller#Action
article_articles GET /article/articles(.:format)
article/articles#index
POST /article/articles(.:format)
article/articles#create
new_article_article GET /article/articles/new(.:format)
article/articles#new
edit_article_article GET /article/articles/:id/edit(.:format)
article/articles#edit
article_article GET /article/articles/:id(.:format)
article/articles#show
PATCH /article/articles/:id(.:format)
article/articles#update
PUT /article/articles/:id(.:format)
article/articles#update
DELETE /article/articles/:id(.:format)
article/articles#destroy
指定したルーティングが正しく作成されていることが確認できました。
コントローラの編集
URLとコントローラが機能しているか、簡単に確認します。
作成した articles_controller.rb を次のように編集します。indexアクションを定義して、インスタンス変数をビューに渡します。
class Article::ArticlesController < ApplicationController
def index
@text = "Article::ArticlesControllerの処理結果を表示しています。"
end
end
インスタンス変数については下記をご参考ください。
【Rails】コントローラの作成方法使い方実例|ビューにデータを渡す方法
ビューの編集
rails g controller で生成された、app/views/article/articles 配下に index.html.erb を作成します。
<%= @text %>
ブラウザで表示する
namespaces と resources で生成されたルートを叩いてみます。
対応するページを開くことができました。
resourcesをネストさせる
resourcesの中にresourcesを記述してネスト構造を作成することもできます。
ネストしたresourcesの使い方と注意点
例えば、商品をまとめたproductsというテーブルの各商品毎に、複数のレビューを記載したreviewsテーブルが紐づいている場合、次のようにURLの構造を明示的にしたいことがあります。
ある商品のレビュー一覧を見るとき /products/:products_id/reviews
その中の一つのレビューの詳細ページを見るとき /products/:products_id/reviews/:id
このような場合に、resourcesのネストが役立ちます。
resources :親のコントローラ名 do
resources :子のコントローラ名
end
ネストさせたresourcesのルート実例
ルーティングに次のようなネストしたresourcesを記述した場合のルーティングの実例です。
ルーティングファイル
Rails.application.routes.draw do
resources :products do
resources :reviews
end
end
ルーティングの確認
ルーティングはrails routes
コマンドで確認できます。
# rails routes
Prefix Verb URI Pattern Controller#Action
product_reviews GET /products/:product_id/reviews(.:format) reviews#index
POST /products/:product_id/reviews(.:format) reviews#create
new_product_review GET /products/:product_id/reviews/new(.:format) reviews#new
edit_product_review GET /products/:product_id/reviews/:id/edit(.:format) reviews#edit
product_review GET /products/:product_id/reviews/:id(.:format) reviews#show
PATCH /products/:product_id/reviews/:id(.:format) reviews#update
PUT /products/:product_id/reviews/:id(.:format) reviews#update
DELETE /products/:product_id/reviews/:id(.:format) reviews#destroy
products GET /products(.:format) products#index
POST /products(.:format) products#create
new_product GET /products/new(.:format) products#new
edit_product GET /products/:id/edit(.:format) products#edit
product GET /products/:id(.:format) products#show
PATCH /products/:id(.:format) products#update
PUT /products/:id(.:format) products#update
DELETE /products/:id(.:format) products#destroy
reivewsのルートがproductsの配下に配置されていることがわかります。
memberとcollection
resourcesは生成するルート(アクション)が決まっています。
resourcesの中で、memberとcollectionを使うことで、独自のアクションを追加することができます。
memberとcollectionの違い
member(メンバー)とcollectoin(コレクション)の違いは、ルートを生成したときに:id
をつけるかどうかの違いです。
処理 | 内容 | 生成されるルートの例 |
---|---|---|
member | :idがつくURIを生成する | /users/:id/info |
collection | :idがつかないURIを生成する | /users/contact |
collectionとは集めるといった集合体の意味なので、全体に共通したデータを扱うためのルートになります。
memberは集団の中の一人の意味なので、個別のデータを扱うためのルートになります。
collectionの使い方
:idなしのパスを生み出すcollectionでルートを指定する方法は2つあります。
- パスとアクションが一致する場合
- パスとアクションが一致しない場合
- on: :collectionを使う
パスとアクションが一致する場合
/users/contactにアクセスして、contactアクションを実行する場合など、URIとアクション名が一致する場合は以下のように書きます。
resources :コントローラ名 do
collection do
メソッド名 :アクション名
end
end
シンボルではなく、文字列で指定しても同じ処理になります。
resources :コントローラ名 do
collection do
メソッド名 'アクション名'
end
end
パスとアクションが一致しない場合
パスとアクションが一致しない場合は、actionオプションを使ってactionを指定します。
resources :コントローラ名 do
collection do
メソッド名 :パス, action: :アクション名
end
end
シンボルではなく、文字列で指定しても同じ処理になります。
resources :コントローラ名 do
collection do
メソッド名 'パス', action: 'アクション名'
end
end
on: :collectoinを使う
collection do ~ end
の処理は、 on: :collectoin
を使った処理に置き換えることができます。
resources :コントローラ名 do
メソッド名 :アクション名, on: :collection
メソッド名 :パス, action: :アクション名, on: :collection
end
memberの使い方
memberの使い方はcollectionと同じです。(上記のcollectionをmemberに変えるだけです)
:idつきのパスを生み出すmemberでルートを指定する方法は2つあります。
- パスとアクションが一致する場合
- パスとアクションが一致しない場合
- on: :memberを使う
パスとアクションが一致する場合
/users/:id/loginにアクセスして、loginアクションを実行する場合など、URIとアクション名が一致する場合は以下のように書きます。
resources :コントローラ名 do
member do
メソッド名 :アクション名
end
end
シンボルではなく、文字列で指定しても同じ処理になります。
resources :コントローラ名 do
member do
メソッド名 'アクション名'
end
end
パスとアクションが一致しない場合
パスとアクションが一致しない場合は、actionオプションを使ってactionを指定します。
resources :コントローラ名 do
member do
メソッド名 :パス, action: :アクション名
end
end
シンボルではなく、文字列で指定しても同じ処理になります。
resources :コントローラ名 do
member do
メソッド名 'パス', action: 'アクション名'
end
end
on: :memberを使う
member do ~ end
の処理は、 on: :member
を使った処理に置き換えることができます。
resources :コントローラ名 do
メソッド名 :アクション名, on: :member
メソッド名 :パス, action: :アクション名, on: :member
end