on programming Rails for fun and profit...

Define New Routes Using the Member and Collection Blocks

This post shows how to define new routes using the member and collection blocks provided by the Rails router.

Define new routes using member and collection blocks
Define new routes using member and collection blocks

A single call to resources in the routes.rb file declares the seven standard routes for your resource. What if you need additional routes? Don't worry. Rails provides the member and collection blocks so you can define custom routes for both the resource collection and the individual resource.

Here's how you'd typically define routes for the article resource.

resources :articles

This creates the following routes.

➜ bin/rails routes -g article

      Prefix Verb   URI Pattern                  Controller#Action
    articles GET    /articles(.:format)          articles#index
             POST   /articles(.:format)          articles#create
 new_article GET    /articles/new(.:format)      articles#new
edit_article GET    /articles/:id/edit(.:format) articles#edit
     article GET    /articles/:id(.:format)      articles#show
             PATCH  /articles/:id(.:format)      articles#update
             PUT    /articles/:id(.:format)      articles#update
             DELETE /articles/:id(.:format)      articles#destroy

But let's say you are writing your articles in markdown, and need to see a preview of the article as you write it.

You could create a PreviewController and display the article's preview using its show action, but it's convenient to add a preview action on the ArticlesController itself.

Custom Member Routes

Here's how you define the preview route on the ArticlesController using the member block.

resources :articles do
  member do
    get 'preview'
  end
end

The Rails router adds a new route that directs the request to ArticlesController#preview action. The remaining routes remain unchanged. It also passes the article id in params[:id] and creates the preview_article_path and preview_article_url helpers.

➜ bin/rails routes -g article

         Prefix Verb   URI Pattern                     Controller#Action
preview_article GET    /articles/:id/preview(.:format) articles#preview

...remaining routes

If you have a single member route, use the short-hand version by passing the :on option to the route, eliminating the block.

resources :articles do
  get 'preview', on: :member
end

You can go one step further and leave out the :on option.

resources :articles do
  get 'preview'
end

It generates the following route.

➜  bin/rails routes -g preview

         Prefix Verb URI Pattern                         Controller#Action         
article_preview GET  /articles/:article_id/preview(.:format) articles#preview

There are two important differences here:

  1. The article's id is available as params[:article_id] instead of params[:id].
  2. The route helpers changes from preview_article_path to article_preview_path and preview_article_url to article_preview_url.

Custom Collection Routes

To add a new route for the collection of a resource, use the collection block.

resources :articles do
  collection do
    get 'search'
  end
end

This adds the following new route. It will also add a search_articles_path and search_articles_url helper.

search_articles GET    /articles/search(.:format)   articles#search

If you don't need multiple collection routes, just pass :on option to the route.

resources :articles do
  get 'search', on: :collection
end

This will add the same route as above.

Conclusion

Rails allows you to break out of its convention of using seven resourceful routes using the member and collection blocks. Both allow you to define additional routes for your resources than the standard seven routes.

A member block acts on a single member of the resource, whereas a collection operates on a collection of that resource.

I hope you found this article helpful, and you learned something new. Let me know in the comments below what you think.

Thanks for reading!

Subscribe to Akshay's Blog

Sign up now to get access to the library of members-only issues.
Jamie Larson
Subscribe