Rails pluck from associated tables - ruby-on-rails

I have two tables
sample
has_many :abundances
self.primary_key = :sample_id
and
abundance
has_many :samples
self.primary_key = :sample_id
In abundances controller i have a ransack search
def index
#search = Abundance.ransack(params[:q])
#abundances = #search.result
#abundancez = #abundances.paginate(:page => params[:page],:per_page => 100)
end
end
in the abundances view, I have a filtered table based on the ransack parameters.
<%= will_paginate #abundancez%>
<% #abundancez.each do |abundance| %>
<td><%= abundance.sample_id %><td>
<td><%= abundance.length %><td>
<td><%= abundance.eff_length%><td>
<td><%= abundance.est_counts%><td>
<td><%= abundance.tpm%><td>
<% end %>
The sample table has a field, race that i want to pull up in the abundances view when via corresponding to the filtered parameters above.
Ive tried to use pluck in the view
<%= will_paginate #abundancez%>
<% #abundancez.each do |abundance| %>
<td><%= abundance.sample_id %><td>
<td><%= abundance.length %><td>
<td><%= abundance.eff_length%><td>
<td><%= abundance.est_counts%><td>
<td><%= abundance.tpm%><td>
<td><%= samples.pluck(abundance.samples_id,:race)%></td>
but i get an error. Not sure if I'm going about this the right way or if I the syntax is incorrect.
Thanks!

The thing here is that you defined that an abundance has_many samples, so you can't return the value of the race for one sample like you are doing here.
as you said in your comments, it seems that your associations are wrong, change your abundance model from has_may, to belongs_to
belongs_to :sample
and then on your view, you can return the race value like this
<%= will_paginate #abundancez%>
<% #abundancez.each do |abundance| %>
<td><%= abundance.sample_id %><td>
<td><%= abundance.length %><td>
<td><%= abundance.eff_length%><td>
<td><%= abundance.est_counts%><td>
<td><%= abundance.tpm%><td>
<td><%= abundance.sample.race %></td>
this because you said in the comments that abundances have a sample_id attribute, so abundance belongs_to a sample. of course this will work if abundance have the attribute of sample_id filled with a valid ID (an existing one sample) and of course, that it has a race value.

Related

Filter with another table's attribute (one to many) in Rails

Filter with another table's attribute (one to many) in Rails
I'm a beginner on rails and currently working on my class project. I have a lead and a lead_comments table, lead has_many lead_comments and lead_comment belong_to lead, which I got those established.
In Model:
class Lead < ApplicationRecord
has_many :lead_comments
end
class LeadComment < ApplicationRecord
belongs_to :lead
end
In my lead's index view, I am trying to setup a date filter base on the Update_at in the lead_comments, which is the attribute from another table:
<div class="date-search">
<%= form_tag leads_path, method: :get do %>
<%= date_field_tag 'date_search[date_from]', #date_search.date_from %>
<%= date_field_tag 'date_search[date_to]', #date_search.date_to %>
<%= submit_tag 'Date Search' %>
<% end %>
</div>
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Phone Number</th>
<th>Last Updated Date</th>
<th colspan="3">Action</th>
</tr>
</thead>
<tbody>
<% #leads.each do |lead| %>
<tr>
<td><%= lead.lead_firstname %></td>
<td><%= lead.lead_lastname %></td>
<td><%= lead.lead_phone %></td>
<td><%= lead.lead_comments.maximum(:updated_at) %></td>
<td><%= link_to 'Detail', lead %></td>
<td><%= link_to 'Edit/Update', edit_lead_path(lead) %></td>
<td><%= link_to 'Remove', lead, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
In my lead controller, I set up another controller for lead search purpose:
def index
#date_search = LeadSearch.new(params[:date_search])
#leads = #date_search.scope
end
In my lead search model, I believe where my problem is:
class LeadSearch
attr_reader :date_from, :date_to
def initialize(params)
params ||= {}
#date_from = parsed_date(params[:date_from], 30.days.ago.to_date.to_s)
#date_to = parsed_date(params[:date_to], Date.today.to_s)
end
def scope
Lead.lead_comments.maximum(:updated_at).where('updated_at BETWEEN ? AND ?', #date_from, #date_to)
end
private
def parsed_date(date_string, default)
Date.parse(date_string)
rescue ArgumentError, TypeError
default
end
end
My lead_comment table only has one attributes, which is comment, along with the two automated date attributes created by Rails, created_at and updated_at.
Whenever I run the application I get an error that tells me undefined method "lead_comments". I thought I have already established the has_many and belong_to relationship and this still not working. Can someone please help me out and guide me to the right direction? Thank you for your time.
you are doing Lead.lead_comments which is wrong. You are using the class name instead of the object. There should be a Lead model's object.
#lead.lead_comments
First, try your query in rails console. then use it in the controller for better perspective. try following,
Lead.lead_comments # will give error
instead use,
Lead.last.lead_comments # success
Issues in your code:
Lead.lead_comments
Let's simplify this: think about lead_comments as a method that given a lead returns its comments. But we need a lead. That's why called on Lead does not work. That would work called on a Lead object.
Lead.lead_comments.maximum(:updated_at)
Here you're composing a SQL query though ActiveRecord but calling maximum stop this composition because that require a value so you're not able to call anything else after methods like maximum
Let's make your code work
def scope
Lead.where('updated_at BETWEEN ? AND ?', #date_from, #date_to)
end
in your view
<td><%= lead.lead_comments.maximum(:updated_at) %></td>
Note here that this code has always been correct because you call lead_comments on a lead object.
I know, this performs one query for each Lead object but to make it works with just one query looks like another question

Rails: `undefined method `per_code' for nil:NilClass` When Chaining Info From Different Object Models

I'm creating an admin page for my app in which there is a table that shows user data. Each user has completed several quizzes. In each quiz (per_quiz, bal_quiz, etc.) there is a code that needs to be reported on this page (the columns are per_code in the per_quiz model, bal_code in the bal_quiz model, etc.
Each user has_one bal_quiz (and per_quiz and so on) and each per_quiz belongs_to a user.
I'm trying to call it like this:
<% #users.each do |u| %>
<tr>
<td><%= u.id %></td>
<td><%= u.first_name %></td>
<td><%= u.last_name %></td>
<td><%= u.per_quiz.per_code %></td>
<td><%= u.bal_quiz.bal_code %> (Balance)
<br><%= u.flex_quiz.flex_code %> (Flexibility)
</td>
</tr>
<% end %>
In my controller I have #users = User.order("last_name DESC").
The error I am getting is undefined method 'per_code' for nil:NilClass called on the <td> line of the view.
Can anyone help me figure out why this isn't working? I have similar erb elsewhere in the app and this syntax works...
It's due to u.per_quiz equals to nil. Use try to solve this problem:
<td><%= u.try(:per_quiz).try(:per_code) %></td>

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.

Referencing a model's Show View form another model's Index view

In the Color Index View, the following produces a clickable link that takes me to the Color Show View.
<% #colors.each do |color| %>
<tr>
<td><%= link_to color.color_name, color_path(color) %></td>
in the model, I have:
class Color < ActiveRecord::Base
belongs_to :product
I also have a Product Index View, and I want to create a clickable link to the Color Show View, but I can't make it work.
This does not work (for one thing, color_name is not the primary key in the color table:
<% #products.each do |product| %>
<tr>
<td><%= link_to product.color_name, product.color_name, color_path(color.color_name) %></td>
in the model, I have:
class Product < ActiveRecord::Base
has_many :colors
This is not working and I'm getting an error when I try the Color Index View, something like:
undefined local variable or method color
Any ideas?
Solution:
Here's what ended up working:
<% color_id = Color.find_by_color_name(product.color_name) %>
<td><%= link_to product.color_name, color_path(color_id) %></td>
It could also obviously be done on a single line, but two lines makes the code more readable (I think)
What I don't understand is why someone found it necessary to downgrade the question.
color.color_name is giving you error because you don't have color object on Product Index View.
Try <td><%= link_to product.color_name, product.color_name, color_path(product.color) %></td> if there is one-to-one relationship
Try <td><%= link_to product.color_name, product.color_name, color_path(product.colors.first) %></td> if there is one-to-many relationship
Your Product has_many colors. Therefore, your code should be something like this:
<% #products.each do |product| %>
<tr>
<% product.colors.each do |color| %>
<td><%= link_to color.color_name, color_path(color) %></td>
<% end %>
</tr>
<% end %>
It iterates on the colors of your each product and shows link to their show path.
Caution: Probably subjected to N+1 problem. Above is just supposed to give you direction.

Identifying Model Instance by Two Relations

I'm trying to pick out an instance of a model ("Package") by its relation to two other models to which it belongs ("Cut" and "Animal"). While there are, say many packages with :cut_id 3 and many with :animal_id 4, there should only be one with both, and I want to pick that one out and display its contents in a table.
I've tried the following DIY mess, and it's not really working. (cutfind is a method I created that I know works for calling out all of the cuts associated with the given animal.)
<% #animal.cutfind.each do |cut| %>
<tr>
<td><%= cut.name %></td>
<td><%= number_to_currency(cut.price) %></td>
<td><%= cut.package_weight %> lb</td>
<% #a = Package.where(:animal_id => #animal.id) %>
<% #pset = #a.where(:cut_id => cut.id) %>
<% #pset.each do |p| %>
<td><%= p.original %></td>
<td><%= p.left %></td>
<% end %>
</tr>
<%end%>
Any idea how to do this [better]? Thanks.
Update: I tried this other DIY mess and am getting the same problem (the cells aren't even being created, which leads me to believe that #pset is empty).
This is in my animal model:
def packagefind
Package.where(:animal_id => self.id)
end
And then I changed the above like so:
<td><%= cut.package_weight %> lb</td>
<% #pset = #animal.packagefind.where(:cut_id => cut.id) %>
<% #pset.each do |p| %>
<td><%= p.original %></td>
<td><%= p.left %></td>
<% end %>
Rails will automatically generate methods to help you find the associated records if you define the following relations:
class Animal
has_many :cuts
has_many :packages, :through => :cuts
end
class Cut
belongs_to :animal
belongs_to :package
end
class Package
has_many :cuts
has_many :animals, :through => :cuts
end
In your controller, the following line will eager load all the records you will need in your view:
#animal = Animal.includes(:cuts => :package)
Your view can then be shortened to:
<% #animal.cuts.each do |cut| %>
<tr>
<td><%= cut.name %></td>
<td><%= number_to_currency(cut.price) %></td>
<td><%= cut.package_weight %> lb</td>
<td><%= cut.package.original %></td>
<td><%= cut.package.left %></td>
</tr>
<%end%>
As I'm not able to comment on your post, I take a guess:
You have the folllowing architecture:
Cut -> Package <- Animal
In this, "->" and "<-" are one-to-many relationships so that
class Package < ActiveRecord::Base
has_many :cuts
has_many :animals
end
So, you want "the" package, that has Cut with id 3 and Animal id 4.
Did you try:
x = Product.select { |product| product.cuts.include?(Cut.find(3)) }.select{ |product| product.animals.include?(Animal.find(4)) }
?
EDIT: I first suggested to you use
Product.find_by_product_id_and_animal_id()
which didn't work but showed the OP the way to do it

Resources