Pass .each loop reference object in Ruby on Rails - 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?

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!

undefined method `name' for nil:NilClass

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

if/else in erb executing code it should not

Thanks to everyone for providing me with information! There were some very quick responses. My solution was to use a clearer test in the if. Grammar for the win!
"You have a nil object when you didn't expect it! The error occurred while evaluating nil.name"
This error points to the line below with "file.name".
I get why it evaluates to nil.name and is empty(it should be) but I don't understand why that code is even executed.
It works by changing the test for if to..
if file[0] != nil
I feel like there's an important detail I'm missing so I'd appreciate some help with understanding this.
In my view I have:
<table>
<tr>
<th>File</th>
<th>Description</th>
</tr>
<% if !#files.empty? %>
<% #files.each do |file| %>
<tr>
<td><%= file.name %></td>
<td><%= file.description %></td>
<td><%= link_to "Download", :controller => "files", :action => "download", :id => file.id %></td>
<td><%= button_to "Delete", { :controller => "files", :action => "destroy", :id => file.id }, :method => "delete" %></td>
</tr>
<% end %>
<% else %>
<tr>
<td><b>No files</b></td>
</tr>
<% end %>
</table>
In the controller I create an empty array called #files and then push in values later when they're created.
Ruby 1.8.7-p72
Rails 2.2.2
What you want in your #files instance var is either an empty array
#files = []
or actual File objects
#files = File.all
but you seem to somehow produce an array that contains nil elements, for example
#files = [nil, <#File>, <#File>]
so #files itself is not nil, while its first element is. Therefore, the following code returns true
#files.any?
which is equivalent to
!#files.empty?
because #files.is_a? Array and not #files.nil?. Your problem must be in the corresponding controller, where you seem to add a nil element to your #files.

Problem while editing a record

i treid to edit one record of my tables in rails 3 but ann error occured like this :
ActiveRecord::RecordNotFound in WordsController#edit
in my controller:
def edit
#adverb =Adverb.find(:id)
end
and in my view i have :
<% #adverb.each do |av| %>
<tr class="<%= cycle("odd", "even") -%>">
<td><%= av.name %></td>
<td><%= av.bedeutung %></td>
<td>
<%= link_to 'edit',{:controller => 'words',:action => 'edit',:id=> av.id} %>
</td>
</tr>
<% end %>
how can i solve this problem?
Try
#adverb = Adverb.find(params[:id])
its just
#adverb = Adverb.find(params[:id])
You dont need the .first option on the end thats only needed when using the where statement
:id is just a symbol, you are looking for that symbol's value inside the params hash
So instead of
Adverb.find(:id)
Use
Adverb.find(params[:id])
This will return a single record that matches the value of :id in params hash that is probably coming form you url /adverbs/:id
If there is no record with the provided ID, then an ActiveRecord::RecordNotFound exception will be raised, which in development will show you a stack trace page, and in production will show a 404 page.

Resources