Nested Route Parameters in Rails

The Rails routing configuration allows you override the named parameters in your routes.

resources :products, only: :show, param: :sku

This generates a path that looks like this:

   Prefix Verb   URI Pattern                 Controller#Action
  product GET    /products/:sku(.:format)    products#show

However, it doesn’t work in certain scenarios. For example, I often find myself wanting to do something like this:

namespace :api do
  resources :products, only: [], param: :legacy_id do
    resources :events, only: :create, controller: 'product_events'
  end
end

Which generates the following path:

   Prefix Verb              URI Pattern                                          Controller#Action
  api_product_events POST   /api/products/:product_legacy_id/events(.:format)    api/product_events#create

It gets akward having to reference params[:product_legacy_id] in your controller, especially if you’ve standardized on variables like legacy_product_id (which reads and sounds better). So how do we specify the parameter in nested routes? We can choose to forego the resources helper:

post '/api/products/:legacy_product_id/events', to: 'product_events#create', as: 'api_product_events'

But this gets tedious and is more error-prone. A better way - in my opinion - is to use nesting with the member helper.

namespace :api do
  resources :products, only: [], param: :legacy_product_id do
    member do
      resources :events, only: :create, controller: 'product_events', as: 'product_events'
    end
  end
end

Which generates the path that I want:

   Prefix Verb              URI Pattern                                          Controller#Action
  api_product_events POST   /api/products/:legacy_product_id/events(.:format)    api/product_events#create