When I heard about nested routes for the first time I was interested to hear how they could improve your overall code. The simplest thing I first understood was that it cleaned up your routing so the URLs looked better than if you didn't have them. This way if you wanted to look at all books written by an author the path would look like /author/:id/books, instead of going to /books and then needing to do extra work to find the author you wanted to render.
I found it interesting though that the route still takes you to the same controller action. This example would be in the Books controller on the index action. So the nested route is nice but you still have to fill out some logic to make the page render what you are actually looking for.
The question presents itself again... What is the benefit of a nested route other than just for looks??? Digging a bit deeper you will find that when using a nested route you do benefit from having an author_id param at your disposal. So before when the route you had was this:
/books, if you wanted to find a specific author you would probably need a form of some sort to send the id to your controller.
But with:
/author/:id/books now you have that author_id so a lot of the work is already done for you. No form is necessary for me to find the correct author. I can just do something like
@author = Author.find_by(id: params[:author_id])
and now I have the author who I am looking for then instead of the index looking like this
def index
@books = Book.all
end
It will look like this
def index
if params[:author_id]
@author = Author.find_by(id: params[:author_id])
@books = author.books
else
@books = Book.all
end
end
Basically what this if statement is telling the controller is, if there is a nested route passed in all I want are those authors books specifically otherwise I want to see all the books in the database.
There is a more tangible advantage to a nested resource. Another advantage you have with a nested resource is the ability to pass a form multiple models. In fact, if you don't pass the form multiple models you will end up with a routing error. Here is an example.
Say I want to create a form for a user to create a new book, but I want the author to be the one whose route we are currently using. /author/:id/book/new would be the route.
If I do this I will get an error that says no author_id attribute can be found.
<%= form_with(model: @book) do |f| %>
<%= f.label :title %>
<%= f.text_field :title %><be>
<%= f.hidden_field :author_id, value: @author.id %>
<%end%>
What we are trying to do is not allow the user to select an author so when they submit the form even though the author is not visible in the form it will still get passed through when creating the new book. Now the problem here is that the author instance variable needs to be passed into the form.
We are able to this because we are using nested routes by the way. This is what the form should look like instead.
<%= form_with(model: [@author, @book]) do |f| %>
<%= f.label :title %>
<%= f.text_field :title %><be>
<%= f.hidden_field :author_id, value: @author.id %>
<%end%>
Now since we are correctly using the power of our nested routes we can access what we need to by using the proper syntax above and including the author instance variable in the form.
There are other benefits to nested routes as well but this is an eye-opening one that can be super helpful when it is needed. What I have learned the most during my development process is that it is ok to not understand something right away. For me, nested routes were nice but didn't make a ton of sense, but the more you use them the more little tricks you will pick up and then start to realize how beneficial they actually are.
Top comments (0)