読者です 読者をやめる 読者になる 読者になる

【Rails】ルート定義について(routes.rb)

Ruby on Rails
スポンサーリンク

Rails のルート定義についてです。

ルート定義の確認方法

ルート定義を確認する方法は次の2通りあります。

  • ブラウザからhttp://localhost:3000/rails/info/routesにアクセス
  • ターミナルから./bin/rake routesまたは Rails 5 の場合./bin/rails routesを実行

結果にはURLヘルパー、HTTPメソッド、URLパターン、コントローラ#アクションが表示され、ブラウザの方が検索できたりURLヘルパーを切り替えたりすることができます。

resourcesメソッド

Rails では原則として RESTful なインターフェースに沿って設計をするのが基本です。REST では HTTPメソッドの GET, POST, PATCH, DELETE で CRUD ( Create, Read, Update, Delete ) を表現します。

routes.rb にresources :usersと定義すると以下のようなURLとアクションがマッピングされ、アクションは UsersController のメソッドに対応付けられています。

URL アクション HTTPメソッド パスプレフィックス
/users(.:format) users#index GET users
/users/:id(.:format) users#show GET user_path(id)
/users/new(.:format) users#new GET new_user_path
/users(.:format) users#create POST -
/users/:id/edit(.:format) users#edit GET edit_user_path(id)
/users/:id(.:format) users#update PATCH -
/users/:id(.:format) users#destroy DELETE -

復数のリソースを定義する場合はresources :users, :books, :authorsのように記述します。

ちなみにrake routesコマンドを実行すると Update アクションにおいてPUTメソッドも表示されていますが、昔の仕様が残っているだけであり、現在においてはPATCHが推奨されています。

 Riding Rails: Edge Rails: PATCH is the new primary HTTP method for updates

単一のリソースを定義

resourcesメソッドは復数のリソースを対象とするのに対してresourceメソッドを使うことで単一のリソースを対象としたルート定義もできます。

主な違いは単一のリソースであるため index アクションが無い事と、show, edit, delete で :id パラメータを要求しない点です。

resource :config

パスとURLヘルパー

_pathヘルパーの場合は相対パスを返すのに対して、_urlヘルパーは絶対URLを返します。/users/:idの GET メソッドであれば以下の通りです。

user_path(@user)  # /users/1
user_url(@user)  # http://localhost:3000/users/1

only/exceptオプション

resourcesメソッドを使用するとリソースに対応する CRUD のルートが自動で定義されます。そのため実際には不要なルートがある場合にはonlyexceptオプションを使用して無効化しておきます。onlyが有効なアクションを表し、exceptが無効なアクションを表します。以下の例は同じ意味です。

resources :users, only: [:index, :show]
resources :users, except: [:create, :new, :edit, :update, :destroy]

constraintsオプション

constraintsオプションを使うとルートパラメータに対して制約条件を付ける事ができます。パラメータ名: 正規表現の形式で指定して下さい。

resources :users, constraints: { id: /\d+/ }

formatオプション

resourcesメソッドで定義されたすべてのルートはデフォルトで(.:format)が付与されています。これによって復数の拡張子の形式で出力フォーマットを指定できますが、復数のフォーマットに対応したくない場合は次のようにします。ちなみに(.:format)のデフォルトは.htmlです。

resources :users, format: false

controllers/asオプション

resourcesメソッドはデフォルトで指定されたリソース名をもとに対応するコントローラを決定し、URLヘルパーを生成します。そのためcontrollerasオプションを仕様することで変更することが可能です。

resources :users, controller: :member  # MemberControllerがマッピングされる
resources :users, as: :member  # members_path, new_member_path のヘルパーになる

namespace/scopeブロック

モジュール配下のコントローラをマッピングするにはnamespaceブロックを使用します。モジュール配下というのはrails g controller Admin::Usersのようにコントローラを生成した場合、controllers/adminフォルダ配下に作成されるコントローラのことです。

このようなコントローラに対してルート定義をするには、以下のようにnamespaceでモジュール名、ブロック配下にリソースを定義して下さい。リソースは復数でも問題ありません。

namespace :admin do
  resources :users
end
...
admin_users GET    /admin/users(.:format)          admin/users#index

この場合、URLには/admin/users/:idのように admin が含まれてしまいますが、scopeブロックを使うことによってURLをモジュールを使用しない状態と同じように扱えます。

scope module: :admin do
  resources :users
end
...
users GET    /users(.:format)          admin/users#index

上記とは逆にモジュールに属さないコントローラに対してURLにプレフィックスを付与したい場合はmodule:指定なしのscopeブロックを使用します。

scope :hoge do
  resources :books
end
...
books GET    /hoge/books(.:format)          books#index

collection/memberブロック

resourcesメソッドで生成されるルート定義は固定ですが、必要に応じて別のアクションを追加することができます。collectionブロックは復数のオブジェクトを扱うアクションに対して、memberブロックは単一のオブジェクトを扱うアクションに対して、それぞれ利用します。

以下のルーティングはGETリクエストの/users/searchパスを認識し、リクエストを UsersController の search アクションにマッピングします。復数オブジェクトを扱うため :id パラメータは含みません。

resources :users do
  collection do
    get 'search'
  end
end
...
search_users GET    /users/search(.:format)     users#search

memberの場合は以下のように記述することでGETリクエストの/books/:id/authorパスを認識し、BooksController の author アクションにマッピングします。単一オブジェクトのため id 値はparams[:id]で渡されます。

resources :books do
  member do
    get 'author'
  end
end
...
author_book GET    /books/:id/author(.:format) books#author

ブロック配下のアクションがひとつである場合は、onパラメータを使ってシンプルに記述できます。

resources :xxxx do
  get 'search', on: :collection
  get 'author', on: :member
end

resourcesメソッドのネスト

リソース同士の親子関係をURLとして表現したい場合はresourcesメソッドのネストを使用します。親のリソースは :id が変わっているのがわかります。

resources :books do
  resources :reviews
end
    book_reviews GET    /books/:book_id/reviews(.:format)          reviews#index
                 POST   /books/:book_id/reviews(.:format)          reviews#create
 new_book_review GET    /books/:book_id/reviews/new(.:format)      reviews#new
edit_book_review GET    /books/:book_id/reviews/:id/edit(.:format) reviews#edit
     book_review GET    /books/:book_id/reviews/:id(.:format)      reviews#show
                 PATCH  /books/:book_id/reviews/:id(.:format)      reviews#update
                 PUT    /books/:book_id/reviews/:id(.:format)      reviews#update
                 DELETE /books/:book_id/reviews/:id(.:format)      reviews#destroy 

shallowオプション

resourcesメソッドのネストを使用した時にshallowオプションを付けることによって、:id パラメータを受け取るアクションはネストされない浅いURLが生成されるようになります。

resources :books do
  resources :reviews, shallow: true
end
   book_reviews GET    /books/:book_id/reviews(.:format)     reviews#index
                POST   /books/:book_id/reviews(.:format)     reviews#create
new_book_review GET    /books/:book_id/reviews/new(.:format) reviews#new
    edit_review GET    /reviews/:id/edit(.:format)           reviews#edit
         review GET    /reviews/:id(.:format)                reviews#show
                PATCH  /reviews/:id(.:format)                reviews#update
                PUT    /reviews/:id(.:format)                reviews#update
                DELETE /reviews/:id(.:format)                reviews#destroy

scope メソッドとshallow_pathオプションを併用することで浅いURLにプレフィックスを付与することができます。

scope shallow_path: :hoge do
  resources :books do
    resources :reviews, shallow: true
  end
end
...
review GET    /hoge/reviews/:id(.:format)            reviews#show

concernメソッドとオプション

concernメソッドを利用することで、復数のルート定義で共通する内容を切り出せます。

concern :additional do
  get :unapproval, on: :collection
  get :draft, on: :member
end

resources :reviews, concerns: :additional
resources :users, concerns: :additional

 Rails のルーティング | Rails ガイド