I'm trying to make a table from 2 different sets of data
My Controller
#data = CompanyBorrower.find(params[:id])
#data1= #data.childs.all
#data2= #data.parents.all
The Table (a snippet)
<% #data1.zip(#data2) do |f1,f2| %>
<tr>
<td><%= f1.company_borrower1.name %></td>
<td><%= f2.company_borrower2.name %></td>
</tr>
<% end %>
But I get "undefined method `company_borrower2' for nil:NilClass". If I remove one or the other set of data it works fine.
I think I know the issue; I think it is because the "data1" returns 5 rows, whilst "data2" would have 1 row. If I switch, it works, but I only get one row!
So I (think) I know the issue, but have no idea how to resolve?
Edit - Updated
Note that company_borrower1 & company_borrower2 use the same model -
CompanyBorrower Model
has_many :childs, :class_name => 'Parent', :foreign_key => 'company_borrower_id'
has_many :parents, :class_name => 'Parent', :foreign_key => 'company_borrower_id1'
Parent Model
belongs_to :company_borrower1, :class_name => 'CompanyBorrower', :foreign_key => :company_borrower_id
belongs_to :company_borrower2, :class_name => 'CompanyBorrower', :foreign_key => :company_borrower_id1
UPDATE 2
If I do the following it works great, but it places what would be columns across rows. I can work with that, but would still prefer to know how to achieve my original question for future reference
<tr>
<% #data1.each do |f1| %><td><%= f1.company_borrower1.name %></td><% end %>
</tr>
<tr>
<% #data2.each do |f1| %><td><%= f1.company_borrower2.name %></td><% end %>
</tr>
if you are using ruby 2.3 or greater version you can make use of Safe navigation operator (&.) instead of try method
<% #data1.zip(#data2) do |f1,f2| %>
<tr>
<td><%= f1&.company_borrower1&.name %></td>
<td><%= f2&.company_borrower2&.name %></td>
</tr>
<% end %>
The safe navigation operator (&.) will return nil if the object equals nil, otherwise it calls the method on the object..So, if you use the safe navigation operator, you need to make sure it will be called on the all methods.For example, I have used safe navigation operator on f2 object , f2&.company_borrower2 will return nil,but here we are calling agin name method on the return value of f2&.company_borrower2.So in oreder to avoid the error, we need to call agian safe navigation operator.
Same thing applies on the usage of try method
<% #data1.zip(#data2) do |f1,f2| %>
<tr>
<td><%= f1.try(:company_borrower1).try(:name) %></td>
<td><%= f2.try(:company_borrower2).try(:name) %></td>
</tr>
<% end %>
My wild guess would be to use try on what’s returned. So instead of this:
<td><%= data1.name %></td>
<td><%= data2.name %></td>
You should do something like:
<td><%= data1.try(:name) %></td>
<td><%= data2.try(:name) %></td>
Related
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
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.
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>
I've got below code passing my model variable to the view
describe "payslips/index.html.erb" do
it "should display the page" do
assign(:income_tax_rates, [
stub_model(IncomeTaxRate.all)
])
render
puts rendered
# expect(rendered).to include()
end
end
Then I have this:
<% #income_tax_rates.each do |tax_rate| %>
<tr>
<td><%= number_to_currency tax_rate[:income_from], :precision => 0 %></td>
<td><%= number_to_currency tax_rate[:income_to], :precision => 0 %></td>
<td><%= tax_rate[:start] %></td>
<td><%= tax_rate[:finish] %></td>
<td><%= tax_rate[:rate] %></td>
<td><%= number_to_currency tax_rate[:premium], :precision => 0 %></td>
</tr>
<% end %>
But this does not seem to be generating anything instead I get empty tds
What could I do to improve this?
RSpec's stub_model expects a constant as an argument such as an ActiveRecord::Base subclass used to define a model. It also expects either additional parameters or a block in order to set the values of the instance of the class.
You've passed in an ActiveModel::Relation, which is the result of a the all, and even if you'd provided the expected class constant, you haven't provided any parameter values.
See the examples for how this is intended to be used at https://www.relishapp.com/rspec/rspec-rails/v/2-3/docs/mocks/stub-model
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