Nithin Bekal

Posts About Notes Slides

Avoid Deeply Nested Routes in Rails

14 May 2010

UPDATE: Code examples have been updated for Rails 3/4. Rails 2 was the latest version when this post was originally written. Also edited some of the content for clarity.

While generating RESTful routes in rails, it is easy to get carried away and generate many levels of nested resources for every level of has_many associations. For instance, I recently wrote something like this in my routes file (where a Course has_many Batches, and a Batch has_many Exams.):

# config/routes.rb
resources :courses do
  resources :batches do
    resources :exams
  end
end

The Rails Guides for routing makes the following recommendation:

Resources should never be nested more than 1 level deep.

Now imagine how you would get the path to edit an exam resource. You’d have to write something like this:

edit_course_batch_exam_path(@course, @batch, @exam)

As we already have the batch_id parameter in the URLs for #show, #edit, #update and #destroy in batches_controller, we only need to nest #index, #new and #create under the course resource. We can rewrite the routes for course and batches as:

resources :courses do
  resources :batches, only: [:index, :new, :create]
end

resources :batches, only: [:show, :edit, :update, :destroy]

We can do the same to route exams, which need only be routed under the batches resources. To avoid all the verbosity involved in the above example, we can make use of a feature called shallow nesting. All of the above can be achieved through this:

resources :courses, shallow: true do
  resources :batches do
    resources :exams
  end
end

We now have nested routes for the #index, #new and #create, while avoiding the unnecessary nesting for the URLs that route to actions where the id is already being passed.

Hi, I’m Nithin Bekal. I work at Shopify in Ottawa, Canada. Previously, co-founder of CrowdStudio.in and WowMakers. Ruby is my preferred programming language, and the topic of most of my articles here, but I'm also a big fan of Elixir. Tweet to me at @nithinbekal.