Railsは意見の分かれるフレームワークであり、その基本原則の1つは設定よりも慣習であることを心に留めておく必要があります。 つまり、よほどの理由がない限り、上記のパターンや命名規則を破ってはいけません。
たとえば、index アクションを get 'cars/index'
としたり create アクションを post 'car/create'
としたりすると、form_for や link_to, redirect_to などのヘルパーメソッドに対する Rails 独自の動作が崩れてしまうでしょう。
意図せずに規約を破った結果は混沌としており、何時間もフレームワークと戦うことになるような、もつれた混乱が生じます。
Singular Resource Routes
単一リソースに対するルートも用意することが可能です。 つまり、current_user
やcurrent_account
に適用されるような、:id
を指定せずに検索できるリソースを指します。 5277>
resource :profile
Nested Routes
時には、リソースを他のリソースの中に入れ子にする必要があります。 たとえば、ガレージにある特定の車の予約を作成したい場合、悪意のあるユーザーによって改ざんされる可能性のあるフォームの隠しフィールドよりも、URL からその車の :id
を取得する方が便利な場合があります。 railsでネストされたリソースを作成する方法は次のとおりです:
resources :cars do
resources :bookings
end
これは、carsにネストされたbookingの7つのCRUDアクションをすべて作成します。 しかし、通常は7つすべてのルートが必要なわけではありません。 また、必要な場合でも、そのすべてがネストされる必要はありません。 私たちが必要とするのは、予約を作成するアクション(ここでは予約を作成するフォームが車のショーアクションにあると仮定します)と既存の予約を編集して更新することだとしましょう。 予約を編集/更新するために車の:id
を知る必要がありますか? 答えは明らかにノーです。 したがって、私のアプリケーションでは、次の URL に応答するようにします:
# to CREATE a booking
POST request to http://my-ruby-garage.com/cars/:id/bookings/create# to EDIT a booking
GET request to http://my-ruby-garage.com/bookings/:id/edit# to UPDATE a booking
PATCH request to http://my-ruby-garage.com/bookings/:id/
次のコードで生成されます:
resources :cars do
resources :bookings, only:
end
resources :bookings, only:
Rails では、シンボルの配列または単一のシンボルをオプション :only
またはその逆 :except
に供給することにより、標準 CRUD ルートから生成すべきものを修正することができます。 単一のリソースに適用するルート (member routes) や複数のリソースに適用するルート (collection routes) も指定できます。
Member routes
RubyGarage の例で続けると、車はガレージに駐車したりガレージから移動したりすることができます。
resources :cars do
member do
patch :park
patch :remove
end
end
上記により、http://my-ruby-garage.com/cars/:id/park
と http://my-ruby-garage.com/cars/:id/remove
にパッチリクエストを送り、コントローラ内で特定の車を見つけ、それに応じてリソースを変更することができます。
Collection routes
同じように、時には複数のリソースに対して同時に何らかのアクションを実行したいことがあります。 たとえば、車のコレクションを一度に駐車したり、撤去したりする必要があるかもしれません。 5277>
resources :cars do
collection do
post :park, as: :bulk_park
post :remove, as: :bulk_remove
end
end
ここで、アプリケーションが http://my-ruby-garage.com/cars/park
と http://my-ruby-garage.com/cars/remove
に応答するように設定し、これらのアクションにそれぞれ bulk_park と bulk_remove という名前を付けています。 名前付きパスを使用して、アプリケーション内の URL パスを生成できることを忘れないでください。 車のコレクションを駐車するためのパス リンクを構築するには、次のように使用できます。
<%= link_to "Park Cars", bulk_park_path, method: :post, class: "button" %>
Namespaced Routes
名前空間ブロック内のリソースの URL パスをプレフィックスし、名前空間と同じ名前のモジュールにある関連コントローラを探そうとします。
namespace :factory do
resources :cars
end
この例では、次のルートを構築します:
Prefix Verb URI Pattern Controller#Action factory_cars GET /factory/cars(.:format) factory/cars#index
POST /factory/cars(.:format) factory/cars#create factory_car GET /factory/cars/:id(.:format) factory/cars#show
PATCH /factory/cars/:id(.:format) factory/cars#update
PUT /factory/cars/:id(.:format) factory/cars#update
DELETE /factory/cars/:id(.:format) factory/cars#destroy
そして、コントローラも名前空間でなければなりません :
class Factory::CarsController < ApplicationController
# ...
end
Scoped Routes
scope
メソッドは、DRY を維持し関連ルーティング規則をバンドルすることができます。 オプションなしで使用する場合、namespace
に似ていますが、関連するコントローラはモジュールで名前空間化する必要はありません。
scope :factory do
resources :cars
end
次のルートを生成します。 ブラウザに http://my-ruby-garage.com/create-a-car
として表示されるパスと、アプリケーション内で create_car
としてこのルートを参照できるようにしたいとします。 ウィザードの各ステップを知っているモジュール Wizard::Car
があります。
scope module: 'wizards', path: 'create-a-car', as: 'create_car' do
Wizard::Car::STEPS.each do |step|
get step, to: "cars##{step}"
end
post :validate-step, to: 'cars#validate_step'
end
上記のコードは、各ステップで同じパターンを作成します。 たとえば、ステップ1はブラウザからURL http://my-ruby-garage.com/create-a-car/step1
でアクセスでき、対応するフォームはhttp://my-ruby-garage.com/create-a-car/validate-step
にポストリクエストを送信し、create_car_step1_path
を呼び出すことでパスを呼び出すことができます。 先ほどの例では、http://my-ruby-garage.com/create-a-car
にたどり着いた人を自動的に最初のステップにリダイレクトさせたいかもしれません。
get 'create-a-car',
to: redirect("/create-a-car/#{Wizard::SpotAccount::STEPS.first}")
Route Defaults
オプションにハッシュを渡すことで、ルートでデフォルトのパラメータを定義できます。
resources :cars do
collection do
get :export, defaults: { format: 'csv' }
end
end
これを使うと、http://my-ruby-garage.com/cars/export
にアクセスすると、cars コントローラで export アクションを呼び出し、対応するコントローラアクションはデフォルトで csv で応答します。
Route Globbing
ワイルドカードセグメント (星印を先頭に持つフラグメント) を使用すると、ルートの残りの部分が特定のパラメーターに一致するように指定することができます。 5277>
get '/rent/*slugs', to: 'cars#index', as: :rent_cars
このルートは http://my-ruby-garage.com/rent/lisbon/suv-sedan
にマッチし、パラメータを “lisbon/suv-sedan” に設定します。 これは、私たちのデータベースに対するルックアップまたはフィルタリングシステムで使用され、リスボンで suv または sedan のタイプの車を見つけることができます。
Route slugs として検索できる Rails モデルにタグ付けするために、この機能を考慮して Slugcatcher という gem を書いています。