【Rails】ルーティングのresourcesとは?意味と使い方|resourceとの違いやネスト、名前空間の指定などをわかりやすく解説

rails-prograshi(プロぐらし)-kv Rails
記事内に広告が含まれていることがあります。
[PR]

Railsのルーティングファイル(routes.rb)の中でresourcesという記述をよく見かけることがあります。

これは、DB操作でよく使う、複数のルーティングをまとめて作成してくれる便利な記述です。

この、resourcesの意味や使い方を解説しています。

resourcesとは?

resourcesとはリソーシズと読み、DB操作に必要な複数のルーティングを一度に生成してくれるものです。

使い方はresoucesの後にコントローラ名を指定します。

※コントローラ名は小文字で指定します。単語が連結している場合はスネークケースで記述します(コントローラのファイル名に合わせます)

resources :コントローラ名
point

コントローラ名の命名規則は複数形が基本です(絶対条件ではありません)。

rails g controller <コントローラ名> <アクション名>でコントローラが生成されます。生成したrbファイル内のクラス名(コントローラクラスといいます)とファイル名も指定した名前に沿って自動で生成されます。

項目(基本的な)命名規則
コントローラ名複数形。アッパーキャメルケースUserNames
コントローラクラス名【自動生成】アッパーキャメルケース。末尾にControllerが追加されるUserNamesController
ファイル名【自動生成】 スネークケースuser_names_controller.rb
注意点

ルーティングファイルのresourcesで指定するアクション名を冒頭大文字(コントローラクラス名)で指定するとエラーになります。

エラー例
Rails.application.routes.draw do
  resources :Users
end

‘Users’ is not a supported controller name. This can lead to potential routing problems. See https://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use (ArgumentError)

↓修正

Rails.application.routes.draw do
  resources :users
end


resourcesで生成されるルート

resourcesを指定すると、次の8個のルートをまとめて生成します。

アクションHTTP動詞パス内容
indexGET/コントローラ名一覧を表示
createPOST/コントローラ名データ追加処理
newGET /コントローラ名/newデータ追加用の画面
editGET/コントローラ名/:id/edit指定したデータを変更する画面
showGET/コントローラ名/:id指定したデータの詳細画面
updatePATCH/コントローラ名/:id指定したデータの更新処理(変更箇所のみ)
updatePUT/コントローラ名/:id指定したデータの更新処理(全体を更新)
destroyDELETE/コントローラ名/:id指定したデータの削除処理

GETメソッドはWEB上に画面を表示するリクエストです。それ以外の処理はデータを送信したり、DBと通信するメソッドです。

PATCHとPUTの違い

PATCHとPUTはどちらも対象のデータを更新するためのHTTP動詞です。

PATCHの場合は、変更があった個所のみを更新します。

PUTは変更箇所と元のデータも含め一式を更新します。

注意点

ルートを生成するのみなので、アクションやビューファイルはコントローラに追加する必要があります。

なお、ルーティング、テーブル、コントローラ、アクション、モデルなどresourcesを使った処理を行う場合は、rails generate scaffoldコマンドを使うと、処理に必要な記述をしたファイル群が自動で生成されます。


ルーティングの対比


ルーティングに記述する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
 
tips

getの書き方は複数あります。例えば以下はどれも同じ処理になります。

get 'home/index', to: 'home#index'
get 'home/index'
get 'home/index', action: :index, controller: 'home'

詳細はこちらをご参考ください。



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

コントローラの詳細については下記をご参考ください。

(参考)【Rails】コントローラの作成方法使い方実例


ルーティングの作成

続いてルーティングを作成します。シンプルに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つのオプションが用意されています。

  1. only (指定したアクションのみ)
  2. 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動詞パス内容
createPOST/コントローラ名データ追加処理
newGET /コントローラ名/newデータ追加用の画面
editGET/コントローラ名/editデータを変更する画面
showGET/コントローラ名データを表示する画面
updatePATCH/コントローラ名/:idデータの更新処理(変更箇所のみ)
updatePUT/コントローラ名/:idデータの更新処理(全体を更新)
destroyDELETE/コントローラ名/: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
point
  • ディレクトリ名もコントローラ名も小文字のスネークケースで指定します。
  • コントローラ作成時に、rails g controller ディレクトリ名/コントローラ名 を使うと対応するファイルの作成が簡単です。

resourcesは複数指定することもできます。

記述したすべてのresourcesにnamespaceで指定したディレクトリ名が追加されます。

  namespace :ディレクトリ名 do
    resources :コントローラ名1, :コントローラ名2, :コントローラ名3,,,
  end


対応するコントローラ

namespaceを使う場合は、コントローラクラスの名前空間も同様の構造になっている必要があります。

クラスに名前空間を指定するには、クラス名の前に 名前空間:: をつけます。

例えば、articleディレクトリ配下に作った、articlesコントローラに対応するコントローラクラス名はArticle::ArticlesControllerとなります。

class Article::ArticlesController < ApplicationController
   (省略)
end


生成されるルート

生成されるルートは、通常のresourcesで生成されるコントローラ名の上に、指定したディレクトリ名が記述されたものになります。

prefixHTTP動詞PathController#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 で生成されたルートを叩いてみます。

http://localhost:3001/article/articles

対応するページを開くことができました。


resourcesをネストさせる

resourcesの中にresourcesを記述してネスト構造を作成することもできます。

ネストしたresourcesの使い方と注意点

例えば、商品をまとめたproductsというテーブルの各商品毎に、複数のレビューを記載したreviewsテーブルが紐づいている場合、次のようにURLの構造を明示的にしたいことがあります。

ある商品のレビュー一覧を見るとき  /products/:products_id/reviews
その中の一つのレビューの詳細ページを見るとき /products/:products_id/reviews/:id

このような場合に、resourcesのネストが役立ちます。

resources :親のコントローラ名 do
  resources :子のコントローラ名  
end
注意点

ネストするのはURI(パス)のみで、コントローラやビューファイルネストしません

ネストした先(内側)のresourcesに対応するコントローラファイルやビューファイルはネストする必要がありません(ネストしてはいけません)。


通常のrails g scaffoldrails g controllerでコントローラやビューを作成した状態のままで問題ありません。

例えば、次のような親子構造のresourcesにした場合もコントローラとビューファイルのディレクトリ構造は並列になります。

▼ルーティング

resources :products do
  resources :reviews
end


▼コントローラとビューファイルのディレクトリ構造

controllers
 |- products
 |- reviews
views
 |- products
 |- reviews

通常のディレクトリの状態でルーティングのみネストできるのが、ネストさせたresourcesの便利な点です。


ネストさせた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の配下に配置されていることがわかります。

あわせて読みたい

実際にネストさせたresourcesで、親と子のそれぞれでDB操作(投稿・編集・一覧・詳細・削除)ができるアプリケーションを作成する方法については下記をご参考ください。

【Rails】ネストしたresourcesをフル活用したアプリケーションの作成方法|_url, _path, form_with modelのエラー対処法


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つあります。

  1. パスとアクションが一致する場合
  2. パスとアクションが一致しない場合
  3. on: :collectionを使う

パスとアクションが一致する場合

/users/contactにアクセスして、contactアクションを実行する場合など、URIとアクション名が一致する場合は以下のように書きます。

  resources :コントローラ名 do
    collection do
      メソッド名 :アクション名
    end
  end

シンボルではなく、文字列で指定しても同じ処理になります。

  resources :コントローラ名 do
    collection do
      メソッド名 'アクション名'
    end
  end
注意点

すべて小文字で指定します。メソッド名を大文字で記述するとエラーになります。

〇 get
× GET


パスとアクションが一致しない場合

パスとアクションが一致しない場合は、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つあります。

  1. パスとアクションが一致する場合
  2. パスとアクションが一致しない場合
  3. on: :memberを使う

パスとアクションが一致する場合

/users/:id/loginにアクセスして、loginアクションを実行する場合など、URIとアクション名が一致する場合は以下のように書きます。

  resources :コントローラ名 do
    member do
      メソッド名 :アクション名
    end
  end

シンボルではなく、文字列で指定しても同じ処理になります。

  resources :コントローラ名 do
    member do
      メソッド名 'アクション名'
    end
  end
注意点

すべて小文字で指定します。メソッド名を大文字で記述するとエラーになります。

〇 get
× GET


パスとアクションが一致しない場合

パスとアクションが一致しない場合は、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


あわせて読みたい

memberとcollectionの実例や、memberでないgetとmemberのgetの違いについては下記をご参考ください。

【Rails】resourcesにルートを追加する方法|routes.rbのmember(メンバー)とcollection(コレクション)とは?違いと使い方を徹底解説

タイトルとURLをコピーしました