Posted over 4 years ago. Visible to the public.

Rails routes: Extracting collection actions into their own controllers

Let's say you have two screens:

  1. Show a given project
  2. Show a report for all projects

Ideally you want both screens to be handled by different controllers like this:

Copy
GET /projects/:id => ProjectsController#show GET /projects/report => Projects::ReportsController#show

What seems like a simple requirement is a little awkward to configure in your routes.
Obviously the report should be a singleton resource, but how can we nest it into the Projects:: namespace?

What does not work is this:

Copy
resources :projects, only: :show do resource :report, only: :show end

If we defined the routes above we would get a report for each project, instead of one report across all projects:

Copy
GET /projects/:id => ProjectsController#show GET /projects/:id/report => Projects::ReportsController#show

Hacks to solve this include renaming the report route to something like /projects_report, or defining
a new collection action ProjectsController#report. But these are all unsatisfying.

What you can do is wrap the sub-resource in a collection block like you would do with custom collection actions:

Copy
resources :projects, only: :show do collection do resource :report, only: :show, controller: 'projects/report' end end

Run rake routes and you get what you wanted in the first place:

Copy
GET /projects/:id => ProjectsController#show GET /projects/report => Projects::ReportsController#show

Solution for legacy Rails versions

What you can do instead is simple re-use the :projects symbol as both a resource and a namespace:

Copy
namespace :projects, as: :project do resource :report, only: :show end resources :projects, only: :show

Note that the routes must appear in this order so projects/report won't match the :projects resource.

Run rake routes and you get what you wanted in the first place:

Copy
GET /projects/report => Projects::ReportsController#show GET /projects/:id => ProjectsController#show

makandra has been working exclusively with Ruby on Rails since 2007. Our laser focus on a single technology has made us a leader in this space.

Owner of this card:

Avatar
Henning Koch
Last edit:
6 days ago
by Henning Koch
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Henning Koch to makandra dev
This website uses cookies to improve usability and analyze traffic.
Accept or learn more