Rails Access Association attributes issue - ruby-on-rails

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>

Related

Rails link_to not working correctly

I am trying to put in a link_to on my table to go to the show action but it is putting the URL as /admin/vulnerabilities.object_id instead of /admin/vulnerabilities/object_id
my index view is:
...
<% #vulnerabilities.each do |vulnerability| %>
<tr>
<td><%=link_to vulnerability.id, admin_vulnerabilities_path(vulnerability) %></td>
<td><%= vulnerability.type %></td>
<td><%=h truncate(vulnerability.description, :length => 80) %></td>
<td><%= vulnerability.published %></td>
<td><%= vulnerability.modified %></td>
<td><%= link_to vulnerability.href, vulnerability.href , target: :_blank %></td>
</tr>
<% end %>
...
I have a show.html.erb template setup and my show action is as follows:
def show
#vulnerabilities = Vulnerability.find(params[:id])
end
From what I can see, this should work but when clicking the links it just redirects to the index page, effectively refreshing it and not using my show page at all.
It would be helpful if you added the relevant parts of your routes.rb file to your question, but I speculate that the problem is that admin_vulnerabilities_path(vulnerability) should be admin_vulnerability_path(vulnerability).
Also, as noted in the comments, it is probably better to use #vulnerability as your instance name since find will return a single record.

Correct way of conditional rendering within a partial in Rails?

I have created a partial for a LineItem that, in my case, emits a <tr> with a couple of <td>s. This works just fine and dandy.
What I'd want to do then, is use the same partial in different places. The original view has plenty of room, so displaying every cell is ok. But another (a sidebar), has much less space, and I'd only want to display two of the 5 cells.
So the question, then, is what is the correct way of implementing this? I'd like for the "full" version to be the default unless otherwise specified, and only use the limited version if a parameter is passed.
Currently I'd probably use the feature of passing locals to a partial and check if a parameter limited is defined, and if so, skip the last N cells. Am I on a right track, and if so, what kind of a variable should I use (can I use symbols for this)?
Current _line_item.html.erb (that I'm somewhat unhappy with)
<tr>
<td><%= line_item.quantity %>×</td>
<td><%= line_item.product.title %></td>
<td class="item_price"><%= number_to_currency(line_item.total_price, unit: '€') %></td>
<% unless defined? limited %>
<td class="remove_item"><%= button_to 'Remove', line_item, method: :delete %></td>
<% end %>
</tr>
Edit: Added current version.
Yes, you are on the right track. You can do something like
<%= render 'partial_name', limited: true %>
and then in the partial:
<% limited ||= false %> # More explicit as to what default value is
<tr>
<td><%= line_item.quantity %>×</td>
<td><%= line_item.product.title %></td>
<td class="item_price"><%= number_to_currency(line_item.total_price, unit: '€') %></td>
<% unless limited %>
<td class="remove_item"><%= button_to 'Remove', line_item, method: :delete %></td>
<% end %>
</tr>

undefined method `ncbi_ref_seq' for #<ActiveRecord::Associations::CollectionProxy []>

Generator has_many:results
Result belongs_to:generator
I want to have a page whereby i can view all the generators and the results.
For example :This is from my generator/index.html
this is from result/index.html
what i want to have is to combine them together and view all the data.
right now this is what i've changed but i get the error message undefined method for ncbi_ref_seq. ( ncbi_ref_seq is an attribute belonging to the class Result )
GeneratorController.rb
def index
#generators = Generator.all(:include => [:results])
end
Generator/index.html.erb
<tbody>
<% #generators.each do |generator| %>
<tr>
<td><%= generator.primer_length %></td>
<td><%= generator.choice %></td>
<td><%= generator.random_primer_generated %></td>
<td><%= generator.c_primer %></td>
<td><%= generator.results.ncbi_ref_seq %></td>
</tr>
<% end %>
Since a generator has many results. When you take generator.results it returns an Active Record Collection, so there would be several records of Results, so you can't just extra a ncbi_ref_seq.
Either you have to loop through generator.results and output each ncbi_ref_seq like so
<% for result in generator.results %>
<%= result.ncbi_ref_seq %>
<% end %>
Or a generator has_one result.

Rails - add a dropdown selection to index with db update on change

I've added dropdown selections to forms before, but am having trouble getting them to work in the index view. I've read the API on this and can't get anything to work.
Basically, I've got a list of all tasks in the index view. I set the default in the db to 'No' in a migration. I want to be able to loop through all the tasks and have a dropdown selection appear with the options no, yes and partly. Then I want to be able to have the db update that task's field with the selection when it is made.
I can't get the dropdown to work - whenever I try using task.select, it says that select is a private method. I apologise, I'm fairly new to rails - any help anyone could give would be fantastic! How do I get the dropdown to work and how do I ensure that the db gets updated when the value is changed?
Thanks!
View code (here's what I have so far) - tasks/index:
<table class="table table-striped table-bordered">
<tr>
<th>Name</th>
<th>Category</th>
<th>Notes</th>
<th>Completed?</th>
<th></th>
<th></th>
<th></th>
</tr>
<% #tasks.each do |task| %>
<tr>
<td><%= task.name %></td>
<td><%= task.category %></td>
<td><%= task.notes %></td>
<td><%= task.select :complete, ['No','Yes','Partly'], :selected => 'No' %></td>
<td><%= link_to 'Show', task %></td>
<td><%= link_to 'Edit', edit_task_path(task) %></td>
<td><%= link_to 'Delete', task, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</table>
UPDATE:
After more research, I've changed the line of code:
<td><%= task.select :complete, ['No','Yes','Partly'], :selected => 'No' %></td>
to:
<% form_for task do |f| %>
<td><%= select :task, :complete, [ ["Yes",2], ["Partly",1], ["No",0]] %></td>
<% end %>
This has stopped throwing up errors when I try and load the page, however, there is nothing where the 'form' should be - and nothing in the source code, these lines are skipped. How can I get this form to appear and how can I get it to change the database when the selection is changed? Thanks!
Suppose that Post::CATEGORIES = ["No", "Yes", "Partly"]
It depends on how you store task.category in your DB.
If it is an integer in (0, 1, 2)
form_for task do |f|
f.select :category, Post::CATEGORIES.map { |c| [c, Post::CATEGORIES.index(c)] }, :selected => task.category, :include_blank => true
end
If it is a string in ("No", "Yes", "Partly")
form_for task do |f|
f.select :category, Post::CATEGORIES, :selected => task.category, :include_blank => true
end
To be able to make a change to your models, you'll of course need to submit the form somehow. You could use one form for all the records with:
One submit button: you'll need to change the form and your update controller to receive multiple tasks
A form per task with multiple submit buttons: your user will need to submit each time he changes the category
Submit using AJAX each time the user changes the category.
Good luck
I think what you're looking for is a form_for and then a f.select. You need to create the form first and then f.select is the drop down. Something like this:
form_for task do |f|
f.select("task", "category", Post::CATEGORIES, {:include_blank => true})
end
replace Post::CATEGORIES with the list of options for the dropdown

Rails - how do you access a foreign key object in a html.erb template? Works in console

I am learning rails by trying to model a collectible card game.
I have a champion model and a rarity model. I have the has_many/belongs_to in the model definition and this works in the console:
c = Champion.find(1)
c.rarity.name
=> "Uncommon"
When I do the same thing in a template, I get
<%= champion.rarity.name %>
undefined method `name' for nil:NilClass
Any ideas on how to get this to work?
This is on Rails 3.2.2.
Update: Full .erb code
<% #champions.each do |champion| %>
<tr>
<td><%= champion.name %></td>
<td><%= champion.rarity.name %></td>
</tr>
<% end %>
If every Champion does not have a Rarity association (some are nil), you can use a .try() to print the name. Otherwise the .each will fail with a NoMethod when one without a Rarity is encountered.
<% #champions.each do |champion| %>
<tr>
<td><%= h champion.name %></td>
<td><%= h champion.rarity.try(:name) %></td>
</tr>
<% end %>
Or the less clever unless nil method:
<% #champions.each do |champion| %>
<tr>
<td><%= h champion.name %></td>
<td><%= h champion.rarity.name unless champion.rarity.nil? %></td>
</tr>
<% end %>
Note: I have also added the h() helper method to encode these for HTML output, though this is done automatically in Rails 3.

Resources