Identifying Model Instance by Two Relations - ruby-on-rails

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

Related

Array#zip not working (undefined method for nil:NilClass)

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>

Rails pluck from associated tables

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.

Rails counting rows with has_many relation

I have:
class Constituency < ActiveRecord::Base
has_many :votes
end
class Vote <ActiveRecord::Base
belongs_to :constituency
end
Now, what I want to do is to create a table, that will show me Name of constituency, number of voters (which is easy, as it is part of the table Constituency) and number of votes that were given in this constituency.
The beginning looks like this:
<% #constituencies.each do |constituency| %>
<tr>
<td><%= constituency.name %></td>
<td><%= constituency.voters %></td>
So now comes my question: how can I count all rows in Votes, but with division based on constituency?
constituency.votes.count should give you the correct count for each different constituency. Hope this helps.
<% #constituencies.each do |constituency| %>
<tr>
<td><%= constituency.name %></td>
<td><%= constituency.voters %></td>
<td><%= constituency.votes.count %></td>

Ordering results in show view

I've got two models - service_request_work_plan where service_request_work_plan has_many work_plan_tasks and work_plan_tasks belongs to service_request_work_plan. The linkage works, associations render properly and I have the code below in my show view for service_reqeust_work_plan, the goal of which is to show the work_plan_tasks in order. The show action works properly, but they are not showing in order (i.e. order_of_exeuction). What am I missing?
<table>
<tr>
<th>Order of Execution</th>
<th>Task</th>
<th>SLO</th>
<th>Task Instructions</th>
</tr>
<% #service_request_work_plan.work_plan_tasks.each do |work_plan_task| %>
<tr>
<td><%= work_plan_task.order_of_execution %></td>
<td><%= work_plan_task.task_name %></td>
<td><%= work_plan_task.task_slo %></td>
<td><%= work_plan_task.task_instructions %></td>
</tr>
<% end %>
</table>
class ServiceRequestWorkPlan < ActiveRecord::Base
attr_accessible :testing_company_id, :work_plan_name, :work_plan_comments
belongs_to :testing_company
has_many :work_plan_tasks
end
class WorkPlanTask < ActiveRecord::Base
attr_accessible :testing_company_id, :task_name, :task_instructions, :service_request_work_plan_id, :task_slo, :order_of_execution
belongs_to :testing_company
belongs_to :service_request_work_plan
end
def show
#service_request_work_plan = ServiceRequestWorkPlan.find(params[:id])
end
Add a .order(order_of_execution: :asc) for work_plan_tasks when querying the database from the controller. See http://guides.rubyonrails.org/active_record_querying.html#ordering
Controller:
def show
#service_request_work_plan = ServiceRequestWorkPlan.find(params[:id]).work_plan_tasks.order(order_of_execution: :asc)
end
Change this line:
<% #service_request_work_plan.work_plan_tasks.each do |work_plan_task| %>
into this line:
<% #service_request_work_plan.work_plan_tasks.all.order(:order_of_execution).each do |work_plan_task| %>
Default order is ascending, so the above line is complete. If you need descending order:
order(:order_of_execution => :desc)

Rails - Accessing one to many variables in a table loop

I've got a simple one to many relationship between tasks and priorities.
class Task < ActiveRecord::Base
attr_accessible :subject, :body, :priority_id, :company_id, :status_id, :user_ids
has_and_belongs_to_many :users
belongs_to :priority
belongs_to :company
belongs_to :status
end
class Priority < ActiveRecord::Base
attr_accessible :name
has_many :tasks
end
From my tasks/show.html.erb view
<%= #task.priority.name %>
This works.
However in my tasks/index.html.erb
<% #tasks.each do |task| %>
<tr>
<td><%= task.subject %></td>
<td><%= task.body %></td>
<td><%= task.priority.name %></td>
<td><%= link_to 'Show', task %></td>
<td><%= link_to 'Edit', edit_task_path(task) %></td>
<td><%= link_to 'Destroy', task, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
The call to task.priority.name does not work.
It throws a NoMethodError.
I'm guessing this is a really stupid newbie mistake but I can't for the life of me figure it out. It would have assumed that the Active Record magic would have filtered down into a look like this.
I guess your NoMethodError comes on nil:NilClass. Try:
<%= task.priority.name if task.priority %>
Are you sure you have well created all the models and links with primary keys in your database? I think you link to a task with a priority id (prority_id) which doesn't exists.
Check your datas.
Given that there is no validation of the presence of priority in task, it's quite possible that you are calling "name" on nil. Validate the presence of priority (with validates_presence_of) or check it exists before printing it as Christoph says.

Resources