Rails: Routing Helpers for Nested Resources

I have nested resources as shown below:

resources :categories do resources :products end 

According to the Rails Guides ,

You can also use url_for with a set of objects, and Rails will automatically determine which route you want:

 <%= link_to 'Ad details', url_for([@magazine, @ad]) %> 

In this case, Rails will see that @magazine is a magazine, and @ad is Ad, and so the magazine_ad_path helper will use it. In helpers such as link_to, you can only specify an object instead of calling url_for completely:

 <%= link_to 'Ad details', [@magazine, @ad] %> 

For other actions, you just need to insert the action name as the first element of the array:

 <%= link_to 'Edit Ad', [:edit, @magazine, @ad] %> 

In my case, I have the following code that was fully functional:

 <% @products.each do |product| %> <tr> <td><%= product.name %></td> <td><%= link_to 'Show', category_product_path(product, category_id: product.category_id) %></td> <td><%= link_to 'Edit', edit_category_product_path(product, category_id: product.category_id) %></td> <td><%= link_to 'Destroy', category_product_path(product, category_id: product.category_id), method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> 

Obviously, this is a little too verbose, and I wanted to cut it using the trick mentioned above from the guides.

But if I changed the Show and Change link as follows:

 <% @products.each do |product| %> <tr> <td><%= product.name %></td> <td><%= link_to 'Show', [product, product.category_id] %></td> <td><%= link_to 'Edit', [:edit, product, product.category_id] %></td> <td><%= link_to 'Destroy', category_product_path(product, category_id: product.category_id), method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> 

None of them work anymore, and the pages complain about the same thing:

 NoMethodError in Products#index Showing /root/Projects/foo/app/views/products/index.html.erb where line #16 raised: undefined method `persisted?' for 3:Fixnum 

What did I miss?

+6
source share
2 answers

The Rails path โ€œautomaticallyโ€ knows which path to use, checking the objects you pass for your classes, and then looking for a controller whose name matches. Therefore, you need to make sure that what you pass to the link_to is the actual object of the model, and not something like category_id , which is just fixnum and therefore has no controller associated with it.

 <% @products.each do |product| %> <tr> <td><%= product.name %></td> <td><%= link_to 'Show', [product.category, product] %></td> <td><%= link_to 'Edit', [:edit, product.category, product] %></td> <td><%= link_to 'Destroy', [product.category, product], method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> 
+5
source

I assume the line with the violation is one of the following:

 <td><%= link_to 'Show', [product, product.category_id] %></td> <td><%= link_to 'Edit', [:edit, product, product.category_id] %></td> 

product.category_id is Fixnum , and routing cannot know that a random number should be displayed on category_id .

Use the previous URLs that you have, they are more readable.

+4
source

Source: https://habr.com/ru/post/985695/


All Articles