Rails: route helpers for nested resources - ruby-on-rails

I have nested resources as 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 an Ad and will therefore use the magazine_ad_path helper. In helpers like link_to, you can specify just the object in place of the full url_for call:
<%= 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 which 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 it is a little too verbose and I wanted to shorten it using the trick mentioned above from rails guides.
But if I changed the Show and Edit 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 %>
Neither of them works any more, and the pages complains 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?

The way Rails is 'automagically' knowing which path to use is by inspecting the objects you pass for their classes, and then looking for a controller whose name matches. So you need to make sure that what you are passing to the link_to helper is the actual model object, and not something like category_id which is just a fixnum and therefore has no associated controller.
<% #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 %>

I'm guessing the offending line is one of these:
<td><%= link_to 'Show', [product, product.category_id] %></td>
<td><%= link_to 'Edit', [:edit, product, product.category_id] %></td>
The product.category_id is a Fixnum and the routing can't know that a random number is supposed to map to category_id.
Use the previous URLs you had, they're more readable.

Related

NoMethodError in Welcome#index - Getting Started with Rails

Screenshot Photo
Need help for this error. I can't figure out what's wrong with the code. I did research for related topics online but I can't find any solution. Below are the codes.
<!-- index.html.erb -->
<h1>Hello, Rails!</h1>
<%= link_to 'My Blog', controller: 'articles' %>
<%= link_to 'New article', new_article_path %>
<table>
<tr>
<th>Title</th>
<th>Text</th>
</tr>
<% #articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.text %></td>
<td><%= link_to 'Show', article_path(article) %></td>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<td><%= link_to 'Destroy', article_path(article),
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
Here's the code from the controller.
# welcome_controller.rb
class WelcomeController < ApplicationController
def index
end
end
Config codes
# routes.rb
Rails.application.routes.draw do
get 'welcome/index'
resources :articles
root 'welcome#index'
end
Any help would be appreciated!
Undefined method each for nil:NilClass
The error is due to #articles is nil. You should define it in the welcome#index
class WelcomeController < ApplicationController
def index
#articles = Article.all
end
end
However you can tweak the index.html.erb to avoid such errors
<% unless #articles.blank? %>
<% #articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.text %></td>
<td><%= link_to 'Show', article_path(article) %></td>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<td><%= link_to 'Destroy', article_path(article), method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
<% end %>
#Pavan's answer is correct and will solve your issue! As you getting started, I decided to write this answer to explain a little more what was happening:
You're routing root to 'welcome#index', i.e., when you hit http://localhost:300/ it you call method index from WelcomeController. We are used to call it index action from WelcomeController.
After run this method, it will (by default) render the file app/views/welcome/index.html.erb. See the pattern? The action name is the same as the file name and the controller name is the same as the folder name containing this file.
In this file you were using #articles. This is a variable that was defined in WelcomeController#index.
Your issue: this variable wasn't defined in the controller, resulting a nil object. I.e, it doesn't existed.
Solution: define this variable as #Pavan suggested.
But you could fall into the same exception again: if you haven't articles saved. To prevent this case you just need to check if #articles is nil, as #Pavan suggested too.
Hope this answer will clarify the issue and the suggestions to solve it!

Can find the bug in SyntaxError ROR

I ran in to this error and I have tried to debug it, but it seems impossible. Im working with Authorization. I'm following One month rails and I'm trapped at "Authorization: Who can? Who can't?"
I'm getting this error SyntaxError in Pins#index, which I can't conclude much form.
I would be really happy if any of you could find the bug!
Link to my github:
https://github.com/SillasPoulsen/Pinteresting
The image clearly says the error
<% #pins.each do |pin| %>
<tr>
<td><%= pin.description %></td>
<td><%= pin.user.email if pin.user %></td>
<td><%= link_to 'Show', pin %></td>
<% if pin.user == current_user %>
<%= link_to 'Edit', edit_pin_path(pin) %>
<%= link_to 'Destroy', pin, method: :delete, data: { confirm: 'Are you sure?' } %>
<% end %>
<% end %> # remove this line
</tr>
<% end %>

How to displaying an specific attributes with a many to many association in rails

I have a two way many-to-many assoication between 3 models: work.rb, category.rb, categorywork.rb
Within the work#index using <%= work.categories %> renders some wonky looking html markup
<% #works.each do |work| %>
<tr>
<td><%= work.name %></td>
<td><%= work.subtitle %></td>
<td><%= work.categories %></td>
<td><%= link_to 'Show', work %></td>
<td><%= link_to 'Edit', edit_work_path(work) %></td>
<td><%= link_to 'Destroy', work, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
I'm trying to target speific attributes of the association like "name".
Unfortunately when using <%= work.categories.name %> it gets weirder with:
How do i target just the name or just the description?
Try this out:
<%= work.categories.pluck(:name) %>

rails path helper doesnt work

Hello im learning Rails on my testing app and i have this code
<% #categories.each do |category| %>
<tr>
<td><%= category.name %></td>
<td><%= link_to 'Show', backend_category %></td>
<td><%= link_to 'Edit', edit_backend_categories(category) %></td>
<td><%= link_to 'Destroy', backend_category, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
and Rake routes shows me this
home_index GET /home/index(.:format) home#index
root / home#index
contact /contact(.:format) home#contact
backend_root /backend(.:format) backend/admin#index
backend_categories GET /backend/categories(.:format) backend/categories#index
POST /backend/categories(.:format) backend/categories#create
new_backend_category GET /backend/categories/new(.:format) backend/categories#new
edit_backend_category GET /backend/categories/:id/edit(.:format) backend/categories#edit
backend_category GET /backend/categories/:id(.:format) backend/categories#show
PUT /backend/categories/:id(.:format) backend/categories#update
DELETE /backend/categories/:id(.:format) backend/categories#destroy
but im getting error that backend_category doesnt exist
here is image
http://www.nahraj-obrazek.cz/?di=213711395092
whats wrong ? Thank you
You must add _path to your link_to helper url, like so
<% #categories.each do |category| %>
<tr>
<td><%= category.name %></td>
<td><%= link_to 'Show', backend_category_path(category) %></td>
<td><%= link_to 'Edit', edit_backend_category_path(category) %></td>
<td><%= link_to 'Destroy', backend_category_path(category), method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
Following Luis answer, any show path needs a reference to an object. So I believe it should be
<td><%= link_to 'Show', backend_category_path category %></td>
Which can also be written as:
<td><%= link_to 'Show', category %></td>

Forms broken after namespace modification

I recently modified my Sessions.rb controller as it was fighting against the Devise Sessions controller for supremacy in my application. It seems to have worked out well. I modified my route.rb as mentioned in the answer.
Now I'm having a couple of issues in the default (without much changes since the scaffold) sessions forms.
config/routes.rb
namespace :classroom do
resources :registrations
resources :sessions
end
classroom/sessions/index.html.erb
<h1>Listing sessions</h1>
<table>
<tr>
<th>Class size</th>
<th>Course</th>
<th>Description</th>
<th>Location</th>
<th>Name</th>
<th>Price</th>
<th></th>
<th></th>
<th></th>
</tr>
<% #sessions.each do |session| %>
<tr>
<td><%= session.class_size %></td>
<td><%= session.course_id %></td>
<td><%= session.description %></td>
<td><%= session.location_id %></td>
<td><%= session.name %></td>
<td><%= session.price %></td>
<td><%= link_to 'Show', session %></td>
<td><%= link_to 'Edit', edit_classroom_session_path(session) %></td>
<td><%= link_to 'Destroy', session, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Session', new_classroom_session_path %>
The following links has stopped working and gives a "Could not find a valid mapping for" error message when loading /sessions/index.html.erb
<td><%= link_to 'Show', session %></td>
td><%= link_to 'Edit', edit_classroom_session_path(session) %></td>
<td><%= link_to 'Destroy', session, method: :delete, data: { confirm: 'Are you sure?' } %></td>
Output of running rake routes:
classroom_sessions GET /classroom/sessions(.:format) classroom/sessions#index
POST /classroom/sessions(.:format) classroom/sessions#create
new_classroom_session GET /classroom/sessions/new(.:format) classroom/sessions#new
edit_classroom_session GET /classroom/sessions/:id/edit(.:format) classroom/sessions#edit
classroom_session GET /classroom/sessions/:id(.:format) classroom/sessions#show
PUT /classroom/sessions/:id(.:format) classroom/sessions#update
DELETE /classroom/sessions/:id(.:format) classroom/sessions#destroy
I'm not too sure how to modify the 'Show' and 'Destroy' part of the link to make them work with the new namespace. Thanks in advance for any help. Much, much appreciated.
Thanks,
Francis
try with:
<td><%= link_to 'Show', classroom_session_path(session) %></td>
<td><%= link_to 'Edit', edit_classroom_session_path(session) %></td>
<td><%= link_to 'Destroy', classroom_session_path(session), method: :delete, data: { confirm: 'Are you sure?' } %></td>
Look at here at a nice answer how to handle links with namespaced routes:
rails using link_to with namespaced routes
The name of the route is presented on the first column of the routes table. You should follow it on the link helper.
They should be:
<td><%= link_to 'Show', classroom_session_path(session) %></td>
<td><%= link_to 'Edit', edit_classroom_session_path(session) %></td>
<td><%= link_to 'Destroy', classroom_session_path(session), method: :delete, data: { confirm: 'Are you sure?' } %></td>

Resources