Routing and Nested Resources

maddie m
Tech at Power
Published in
3 min readJul 15, 2020

--

by: Madison McCardle, Student Developer

User-friendly and RESTful way:

REST review: it stands for REpresentational State Transfer and encapsulates a way of structuring a URL so that access to specific resources is predictable and standardized.

For example, if you make an app about shoes, navigating to /brands will show an index of all brands objects. If you want to view a specific brand, we can guess the URL for that (as long as we know the brand's id) by going to /brands/:id.

The /:id notation above represents a dynamic route segment.

Continuing with the shoe app example, we want to end up with /brands/1/shoes for all of a brand’s shoes and /brands/1/shoes/5 to see an individual shoe of that brand. To do this, rails allows you to nest resource routes.

Nested Resource Routes

Nested resources give a way to document a parent/child relationship in routes and, ultimately, URLs.

Continuing with our shoe app example, a brand has_many :shoes and a shoe belongs_to :brand. Since a shoe can logically be considered a child object to a brand, it can also be considered a nested resource of a brand for routing purposes.

In a config/routes.rb file, it would look like:

resources :brands, only: [:show] do
resources :shoes, only: [:index, :show]
end

Above you can see the resourced :brands route; by adding the do...end we can pass it a block of its nested routes. You can still do things to the nested resources that we do to a non-nested resource, like limit them to only certain actions. In this case, we only want to nest :show and :index under :brands.

Nested Route URL Helpers

Just like any other resourced route, Rails provides named helpers for our nested routes as well. And, just like most other things Rails provides, there’s a predictable way to figure out what they are.

If we want to get to all shoes nested under a brand, and knowing the URL is /brands/:brand_id/shoes, we can use brand_shoes_path(brand). It's the singular brand because we are getting one by id, and rails infers the id from the url_helper object (in this case brand) you pass it.

Just to mention, you could also pass in brand_shoes_path(brand_id) and that would function the same, but it is not the conventional way to use the url_helper. Instead of passing it an ID, it’s better to pass url_helpers objects because, again, Rails infers the id from the object you pass it.

To apply this to a single shoe for a brand (shoe being a nested resource), that would combine the conventions for the single brand path and single shoe path, leaving us with brand_shoe_path(brand, shoe).

If you’re not sure, or if you just want to double-check, you can use rake routes (or rails routes) on the command line to get a printout of all your named routes.

Using rake routes is easy, but the output might be overwhelming once a project gets to a certain size:

Shoe app project with other routes, some nested and some non-nested. Example of a larger project and all of it’s routes.

You can grep the output of any command to search for what you want. So in the example above, if you just wanted to search for routes related to shoes, you could type rake routes | grep shoes to get a filtered list:

Filtered list of routes related to shoes of a larger shoe app project; visually less overwhelming.

Conclusion

Nesting resources is a powerful tool that helps keep routes neat and tidy and is better than dynamic route segments for representing parent/child relationships in your system.

However, as a general rule, you should only nest resources one level deep and ensure that you are considering Separation of Concerns in your routing.

This post is written by a Power Code Academy Student Developer.

--

--