undefined method `name' for nil:NilClass - ruby-on-rails

I have this problem on te line
<td><%= h box.manufacturer.name %></td>
of
<% #boxes.each do |box| %>
<tr>
<td><%= h box.manufacturer.name %></td>
<td><%= h box.model %></td>
<td><%= link_to 'Mostrar', :action => 'show', :id => box %></td>
<td><%= link_to 'Editar', :action => 'edit', :id => box %></td>
<td><%= button_to 'Eliminar', { :action => 'destroy', :id => box },
:confirm => "Are you sure you want to delete box #{box.model}?" %></td>
manufacturers is a table with field called name,its supposed that an object manufacturer has member called name ,isn it?

It's quite clear one of your box records doesn't have its associated manufacturer. If it's acceptable, you can use Object#try method, like this:
<%= box.manufacturer.try(:name) %>
If it's not, you should think of adding proper validation to Box model:
validates_presence_of :manufacturer
I didn't use h helper because in Rails >= 3.0 (which you probably use) untrusted content is escaped automatically.

It means your one of your boxes doesn't have a manufacturer.
You can prevent an exception like this by using try:
box.try(:manufacturer).try(:name)
If the manufacturer doesn't exist, it will return nil instead of throwing an exception

Yes, but in your case you seem to have a box with no manufacturer.
<%= h box.manufacturer.name if box.manufacturer %>
Or
<%= h box.manufacturer.try(:name) %>

The proposed solutions fix the issue but don't address the bug in architecture. I recommend learning the Tell Don't Ask principle.
Your views shouldn't do any checks on nil as it is not their responsibility. You should always try to avoid long method chains as it will always fail on certain step.
Refactor your application like this:
box.rb:
def manufacturer_name
manufacturer.try(:name)
end
view:
<td><%= h box.manufacturer_name %></td>
I don't think it's possible if the box is nil. If it is - then I recommend removing nils from the array before iterating over it in views like this:
controller:
#boxes = box_retrieving_method_with_nils.compact

Related

Rails Access Association attributes issue

I have an html table that renders a partial as follows
<tbody id="horse_logs">
<%= render #horse_logs %>
</tbody>
This calls _horse_log.html.erb and iterates through each element in #horse_logs
<tr id="<%= dom_id(horse_log) %>">
<td><%= horse_log.id %></td>
<td><%= horse_log.name %></td>
<td><%= horse_log.boarder.first_name%></td> <!-- This is the association I want to access -->
<td><%= horse_log.arrival_date %></td>
<td><%= horse_log.monthly_boarding_fee %></td>
<td><%= link_to '<i class="link blue large id card icon"></i>'.html_safe, horse_log_path(horse_log)%></td>
<td><%= link_to '<i class="link green large edit icon"></i>'.html_safe, edit_horse_log_path(horse_log), remote: true %></td>
<td><%= link_to '<i class="link red large remove icon"></i>'.html_safe, horse_log_path(horse_log), method: :delete, :data => {:confirm => 'Are you sure?'}, remote: true %></td>
</tr>
The issue is that accessing the boarder association inside the partial gives the following error
undefined method `first_name' for nil:NilClass
So basically the way rails implements this, they seem to be stripping the association data. The association is set up in my models correctly, and I can access the data in all other ways EXCEPT inside the partial.
How can I force rails to include the entire association.
here is my controller method if this helps
def index
#horse_logs = HorseLog.all.paginate(:page => params[:page], :per_page => 9).order("created_at DESC")
#horse_log = HorseLog.new
end
There may be a better way to do this but I would try.
<tbody id="horse_logs">
<% #horse_log.each do |horse_log| %>
<%= render 'horse_logs', horse_log: horse_log %>
<% end %>
</tbody>
If you get the same error, then you will need to make sure that your association is set up correctly.
Does every horse_log have a boarder? If not, you will get this error every time you run this code. you will need to check that hourse_log.boarder isn't nil.
For a quick fix, try this. It will prevent the error and return nil gracefully
<td><%= horse_log.try(&:boarder).try(&:first_name) %></td>

How to update instance with params of another instance from a view

I want to write a method that changes a WorkShift to booked:true and booked_by:current_member.member_id. However I get the error
"undefined method `book' for #< WorkShift:0xc973ce0>"
and I don't understand why. I just want it to be a button and not a separate edit view.
Edit: Turns out I put the book method in the wrong place, but the same method in work_shifts.rb throws a "undefined method `to_model' for true:TrueClass" instead. I'm (obviously) unsure what is the correct way to call a custom method that updates one object with the params of another from a view.
My index view:
<% #work_shifts.each do |work_shift| %>
<tr>
<td><%= work_shift.date %></td>
<td><%= work_shift.booked_by %></td>
<td><%= work_shift.booked %></td>
<td><%= work_shift.start_time.strftime("%H:%M") %></td>
<td><%= work_shift.stop_time.strftime("%H:%M") %></td>
<td><%= button_to 'Book', work_shift.book(current_member) %></td>
<% if current_member.admin? %>
<td><%= link_to 'Edit', edit_work_shift_path(work_shift) %></td>
<td><%= button_to "Ta bort", work_shift, :method=>:delete, :work_shift=>:destroy %></td>
<% end %>
</tr>
<% end %>
WorkShift.rb:
def book(member_id)
self.update(booked:true, booked_by: member_id)
end
routes.rb
resources :work_shifts do
member do
get 'book'
end
end
I'm new to rails and learning on the go, and I'm guessing the solution is trivial, but I just can't find any questions or documentation that helps with what I want to do.
Since you're trying to modify a resource's single field, the book link should be a PATCH request and not GET.
Change your routes to
resources :work_shifts do
member do
patch 'book/:member_id' => 'work_shifts#book', as: 'book'
end
end
This will generate the following route
book_work_shift PATCH /work_shifts/:id/book/:member_id(.:format) workshifts#book
And update your book action as
def book
#work_shift = WorkShift.find(params[:id])
#work_shift.book(params[:member_id])
# redirect to some view
end
And modify your model method accordingly.
def book(member_id)
self.update(booked:true, booked_by: member_id)
end
And replace the your view from
<%= button_to 'Book', work_shift.book(current_member) %>
to a link (You can style it as a button if you want)
<%= link_to 'Book', book_work_shift_path(work_shift, current_member.member_id), method: :patch %>
Thats it!

Rails resources routes miss parameters yet match documentation

Using Rails' resources directive, I have created a set of routes for a controller (contacts). I'm now editing the default views they come with to include some of my own content. However, the link_to method is failing, telling me that I'm missing a required parameter.
No route matches {:action => 'show', :controller => 'contacts', :id => nil} missing required keys [:id]
It's obvious why this is happening - the link_to method is not being supplied with an ID, instead it's getting nil. However, the code I'm using matches the documentation for link_to.
This is the view in question:
<% #contacts.each do |contact| %>
<tr>
<td><%= contact.first %></td>
<td><%= contact.last %></td>
<td><%= contact.title %></td>
<td><%= contact.city %></td>
<td><%= contact.phone %></td>
<td><%= contact.email %></td>
<td><%= link_to 'Show', contact %></td>
<td><%= link_to 'Edit', edit_contact_path(contact) %></td>
<td><%= link_to 'Delete', contact.id, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
#contacts is a set of contacts returned from the controller. The line that sets that is:
#contacts = Contact.select("title, first, last, city, phone, email")
.where("created_by" => #current_user.id)
The relevant content of the routes.rb file is simply resources :contacts.
The documentation states:
Because it relies on url_for, link_to supports both older-style controller/action/id arguments and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base your application on resources and use [...]
link_to "Profile", #profile
This appears to be what I'm using with link_to 'Show', contact.
Why is the ID not getting passed to link_to?
What can I do to remedy this?
Change
Contact.select("title, first, last, city, phone, email")
to
Contact.select("title, first, last, city, phone, email, id")
the contact's id is nil because it isn't in the select query.
Also, although it doesn't seem to be causing problems right now, I would reccomend using an array of symbols instead of a comma-separated string, so that the sql query is more specific. For example:
Contact.select("title, first").to_sql #=> SELECT title, first FROM contacts
Contact.select(:title,:first).to_sql #=> SELECT "contacts"."title", "contacts"."first" FROM contacts
This way if you do a join with another model, it won't complain about the unspecific id in select. If you feel like you're typing too much, you can use the %i(...) syntax:
Contact.select(*%i(title first last city phone email))
Your code seems fine.
Maybe you have an instance in the #contacts array that is not saved and therefore, has no id?
Another way to put the same (again, your code is fine) would be:
= link_to 'Show', contact_path(contact)
I would suggest posting the routes file.

Pass .each loop reference object in Ruby on Rails

I am writing a code in ruby on rails where I am creating dynamic rows in table which involves a .each loop. I want to pass the .each loop reference object but it gives me an error.
Following is the code:
<% pworkflows.workflow_executions_list.each do |wf| %>
<tr>
<td><%= wf.execution_status %></td>
<td>
<% if(wf.start_timestamp != nil) %>
<%= wf.start_timestamp.localtime; %> UTC
<% end %>
</td>
<td><%= wf.close_status %></td>
<td><%= wf.execution.run_id %></td>
<td><%= button_to "Details",{ :controller => "pages", :action => "mainpage",:rulesetinstance=>rInsId, :ndetails=>wf} %></td>
</tr>
<% end %>
:ndetails=>wf gives an error. wf is not being recognized as a correct syntax to send.
Please suggest a way.
the error being:
undefined local variable or method `id' for #<ComRuleManagement::WorkflowExecutionObject:0x00003da1751528>
When you do this
<%= button_to "Details",{ :controller => "pages", :action => "mainpage",:rulesetinstance=>rInsId, :ndetails=>wf} %>
you are building an html tag. (since button_to is an html helper). The extra options you pass through, in this instance ":rulesetinstance" and ":ndetails" will be used to make extra attributes in the element, like rulesetinstance="123". However, if you pass the wf object through, then rails will call to_s on it, and you'll end up with something that looks like this ndetails="#<Wf:0x7f518dfc6e68>". This is almost certainly not what you want in your html element. Should you be calling another method of the wf object instead?

email Model and email column clashing in Rails

I have a Submitter Model which has an email column. I also have an Email Model that has email suffix column in it.
My issue (I believe) is that since my Submitter Model has an email column, when I try to use submitter.email.suffix to display the suffix in my Email model it says there's no defined method.
Any idea what I can do here?
View:
<% #submitters.each do |submitter| %> <tr>
<td><%= submitter.school.name %></td>
<td><%= submitter.first_name %></td>
<td><%= submitter.last_name %></td>
<td><%= submitter.email %><%= submitter.email.suffix %></td>
<td><%= link_to 'Show', submitter %></td>
<td><%= link_to 'Edit', edit_submitter_path(submitter) %></td>
<td><%= link_to 'Destroy', submitter, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
As a side note I have no problem showing the IDs of the emails suffix but obviously I'm trying to show the actual suffix instead:
<td><%= submitter.email %><%= submitter.email_suffix_id %></td>
Submitter.rb has a has many :emails and Email.rb has a belongs_to :submitter association.
So let's break this down. You say you're trying to do
submitter.email.suffix
however, your model has no such :email association. Instead you've stated your Submitter model has
has_many :emails
This would mean:
To print the :email attribute on some Submitter instance submitter, use
puts submitter.email
To print the :prefix attribute of each Email instance related to submitter via your has_many association, you'd need to loop over them
submitter.emails.each do |e|
puts e.suffix
done
It's still quite unclear what exactly you're trying to do, but hopefully this clears up some confusion on your end; there is no method naming conflict so far.
submitter.email.suffix won't work because it returns Submitter "email" which is a string, not the Email instance.
submitter.emails.each(&:suffix)
should work. submitter.emails will return an Email's instances and they do have suffix method(according to your words).

Resources