Tasteful Routes

Published: May 30, 2011

I was browsing Github today when I noticed the URL pattern they had employed for Pull Requests 2.0. The index is at /pulls as you’d expect, however the show action was in the format of /pull/1. Here’s an example. I actually think it’s rather nice and reads better than the Rails default of /pulls/1.

Here is how to corral Rails into giving you these types of links for a collection and a nested collection (excuse the Ruby 1.9 hash syntax):

  match 'jobs' => 'jobs#index', as: :jobs
  match 'jobs' => 'jobs#create', via: :post

  resources :job, controller: 'jobs', except: [:index, :create] do
    match 'items' => 'items#index', as: :items
    match 'items' => 'items#create', via: :post
    resources :item, controller: 'items', except: [:index, :create]
  end

This gives you the following:

$ rake routes
         jobs GET    /jobs(.:format)                      {:action=>"index", :controller=>"jobs"}
              POST   /jobs(.:format)                      {:action=>"create", :controller=>"jobs"}
          job GET    /job/:id(.:format)                   {:action=>"show", :controller=>"jobs"}
     edit_job GET    /job/:id/edit(.:format)              {:action=>"edit", :controller=>"jobs"}
              PUT    /job/:id(.:format)                   {:action=>"update", :controller=>"jobs"}
              DELETE /job/:id(.:format)                   {:action=>"destroy", :controller=>"jobs"}
      new_job GET    /job/new(.:format)                   {:action=>"new", :controller=>"jobs"}
    job_items GET    /job/:job_id/items(.:format)         {:action=>"index", :controller=>"items"}
              POST   /job/:job_id/items(.:format)         {:action=>"create", :controller=>"items"}
     job_item GET    /job/:job_id/item/:id(.:format)      {:action=>"show", :controller=>"items"}
edit_job_item GET    /job/:job_id/item/:id/edit(.:format) {:action=>"edit", :controller=>"items"}
              PUT    /job/:job_id/item/:id(.:format)      {:action=>"update", :controller=>"items"}
              DELETE /job/:job_id/item/:id(.:format)      {:action=>"destroy", :controller=>"items"}
 new_job_item GET    /job/:job_id/item/new(.:format)      {:action=>"new", :controller=>"items"}

Update: I’ve created a gem to more easily acheive this. You can read about it on the Icelab blog.