Retrieve info from last record of association - ruby-on-rails

I have a model Lead which has a has_many Relationship with Activity.
I want to display a list of all leads on the leads index page, including a count of all activities and the timestamp of the latest activity of each lead.
The model looks like this:
class Lead < ActiveRecord::Base
has_many :activities, -> { order("activitytimestamp DESC") }, dependent: :destroy
class Activity < ActiveRecord::Base
belongs_to :lead
The view looks like this:
<table>
<thead>
<tr>
<th>Activity | last</th>
...
</tr>
</thead>
<tbody>
<% #leads.each do |lead| %>
<tr>
<td><%= lead.activities.size %> | <%= lead.activities.last %></td>
...
</tr>
<% end %>
</tbody>
</table>
Obviously lead.activities.last doesn't work.
What do I need to do to display the timestamp of the latest lead.activities Record?

You're so close!
General configuration of a general attribute of the most recent record related to a specific record is:
specific_record.related_records.last.general_attribute
or, in your case, I believe:
lead.activities.last.timestamp_field
The issue with
leads.activities.last
is that it returns the object, not the information in the field of that object, which is what you're looking for.

Related

How to list a double nested attribute values on 'index' view?

I have 3 relevant tables to this problem: 'djobs', 'rigs', and 'photographers'. A djob has_many rigs, and a rig has_one photographer. Currently on my djob index screen I have a table where I am listing djob values and rig values, but I don't know how to also display photographer values.
I'm not really sure where to begin with this, so all I've tried is ensuring the models are associated correctly.
Here's my code:
djobs controller:
def index_photography
#djobs = Djob.order(:id).joins(:rigs, :photographers)
end
djobs model:
class Djob < ActiveRecord::Base
has_many :rigs
has_many :photographers, :through => :rigs
accepts_nested_attributes_for :rigs, allow_destroy: true
accepts_nested_attributes_for :photographers
end
djobs index view:
<tbody>
<% #djobs.each do |djob| %>
<tr>
<td><%= link_to 'Edit', edit_djob_path(djob, q: params[:q], :type => "photography") %></td>
<td class="dotted" ><%= djob.jobtype %></td>
<td class="dotted" ><% djob.rigs.each do |rig| %><%= rig.name %></br><% end %></td>
<td class="dotted" ><% djob.rigs.photographers.each do |photographer| %><%= photographer.name %></br><% end %></td>
</tr>
<% end %>
</tbody>
rig model:
class Rig < ActiveRecord::Base
belongs_to :djob
has_one :photographer
accepts_nested_attributes_for :photographers
end
photographer model:
class Photographer < ActiveRecord::Base
belongs_to :rig
end
This code gives me the error: "No association found for name `photographers'. Has it been defined yet?". All I want is for the table to display the photographer's name associated with that particular rig.
Edit: I tried the suggest code from an answer below using this as my code:
<td class="dotted" ><% djob.photographers.each do |photographer| %><%= photographer.name %></br><% end %></td>
and I also fixed my association model code for rigs and djobs.
And while it didn't give me any errors as I had before, there are no photographers showing at all. It's totally blank now. I don't know how to fix this issue. I know for a fact photographers are associated to rigs that are associated to the djob. And the rigs are displaying. So I'm not sure why the photographers aren't showing up at all for me. I'm open to new ideas.
I suppose the problem is here
<td class="dotted" ><% djob.rigs.photographers.each do |photographer| %><%= photographer.name %></br><% end %></td>
should probably be (to display all photographers associated with djob)
<td class="dotted" ><% djob.photographers.each do |photographer| %><%= photographer.name %></br><% end %></td>
or
<td class="dotted" ><% djob.rigs.each do |rig| %><%= rig.photographer.name %></br><% end %></td>
to display single photographer for each rig.
The reason of an error is that your djob model has many photograpers (plural form), but rig has only one photograper.

Trying to display records from chained models on Rails 5.2

Following on from this question
class CoffeeRoast < ApplicationRecord
has_many :coffee_blends
has_many :coffee_beans, through: :coffee_blends
has_one :country, through: :coffee_beans
end
class CoffeeBean < ApplicationRecord
has_many :coffee_blends
has_many :coffee_roasts, through: :coffee_blends
belongs_to :country
end
class Country < ApplicationRecord
has_many :coffee_beans
end
class CoffeeBlend < ApplicationRecord
belongs_to :coffee_bean
belongs_to :coffee_roast
end
I am able to show the related coffee_beans on the coffee_roasts show page, and also the country, however, I can not work out how to display them correctly.
My current code is attempting to show the bean and its related country on the same row on the table, however the top is blank and the two countries are both in the second row.
coffee_roasts/show.html.erb
<h1 class="display-3"><%= #coffee_roast.name %></h1>
<p>
by <h2 class="display-6"><%= #coffee_roast.roaster.roaster_name %></h2>
</p>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Bean</th>
<th>Country</th>
</tr>
</thead>
<tbody>
<% #coffee_roast.coffee_blends.each do |blend| %>
<tr>
<th><%= blend.coffee_bean.name %>
<% end %></th>
<th><%= #coffee_roast.coffee_beans.map {|cb| cb.country.country_name }.join(', ') %></th>
</tr>
</tbody>
</table>
Bean | Country
El Martillo |
Finca La Cumbre | El Salvador, Guatemala
El Salvador show be in-line with the El Martillo bean.
My approach feels quite wrong here, but I'm pretty new to working with multiple levels of models so still learning.
How can I get the beans associated country to display alongside the bean?
This was actually a lot simpler than I thought. I've found the below works perfectly. No need to map an array.
<tbody>
<% #coffee_roast.coffee_blends.each do |blend| %>
<tr>
<td><%= blend.coffee_bean.name %></td>
<td><%= blend.coffee_bean.country.country_name %></td> #this bit was the original concern.
<td><%= blend.coffee_bean.variety %></td>
<td><%= blend.coffee_bean.process %></td>
<% end %>
</tr>
</tbody>
<tbody>
<% #coffee_roast.coffee_blends.each do |blend| %>
<tr>
<td><%= blend.coffee_bean.name %></td>
<td><%= #coffee_roast.coffee_beans.map {|cb| cb.country.country_name }.join(', ') %></td>
</tr>
<% end %>
</tbody>
try and see if this works?

Rails displaying table data dynamically

Models
class Smoothval < ActiveRecord::Base
has_many :smoothings
has_many :steps
end
class Step < ActiveRecord::Base
belongs_to :usdzar
belongs_to :smoothing
belongs_to :smoothval
default_scope lambda {
order(id: :desc)
}
end
class Usdzar < ActiveRecord::Base
has_many :smoothings
has_many :steps
end
The index view that I am trying to achieve:
<table><thead>
<tr>
<th>Smoothing1</th>
<th>Smoothing2</th>
</tr></thead>
<tbody>
<tr>
<td>"finalsmprice","stepnum"</td>
<td>"finalsmprice","stepnum"</td>
</tr>
</tbody>
</table
So all the fsmprices and the stepnums for every smoothval from the steps table
My index.html.erb looks like this:
<h1>Listing Steps</h1>
<table class="table table-striped table-bordered table-condensed">
<thead>
<% Step.all.includes(:smoothval).group_by(&:smoothval_id).each do |smoothval_id, steps| %>
<tr>
<th>
Smoothing: <%= smoothval_id %>
</th>
</tr>
</thead>
<tbody>
<% steps.each do |step| %>
<tr>
<td>
(<%= step.fsmprice %>): <%= step.stepnum %>
</td>
<% end %>
</tr> </tbody>
<% end %>
</table>
The table is very long and obviously displays all headings and data after one another. I have tried to create a postgres pivot table but that failed using tablefunc so back trying to do it in rails
In my controller I can get the smoothvals (the table headings) into an array as follows, the array looks like [1, 5]:
sv = Smoothval.where('id IN (SELECT DISTINCT(steps.smoothval_id) FROM steps)')
#assigned = sv.pluck(:id)
How can I get the above table layout
Thanks
This was too difficult and came accross a post that said its best to create a pivot table
HOWEVER thats not so easy in Postgres, the issue with the tablefunc extension is that it doesnt dynamically assign the columns, so they need to be statically assigned. So I went this route for now and tested the function https://github.com/hnsl/colpivot
I stuck with the basics and did this but will need to think more about refactoring the solution.
SELECT c_crosstab('Select * from steps', 'ct_view', 'id', 'smoothval_id', 'stepnum', 'first');
SELECT *
FROM crosstab(
'SELECT usdzar_id, smoothval_id, stepnum
FROM steps
ORDER BY 1,2 ASC') -- needs to be "ORDER BY 1,2" here
AS ct ("SV" int, "Smooth1" int, "Smooth2" int, "Smooth3" int);
Hope this helps somoene else

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)

has_many form with nested attributes for existing objects

I am still fairly new to Rails and fairly sure the way I'm attempting to go about this is inefficient or just plain silly, but here's what I'm trying to accomplish. I have 2 models, Cases (patient case files) and Inventories (medical transplant materials used in Cases).
class Case < ActiveRecord::Base
has_many :inventories
accepts_nested_attributes_for :inventories, :reject_if => :all_blank
end
class Inventory < ActiveRecord::Base
belongs_to :case
end
Inventories are created through a separate process and the goal is to associate them with a Case through the Case form. What I am trying to do is put a table on my Case form that lists the available Inventories along with checkboxes to select the desired Inventories to associate with the Case being created. This is further complicated by the fact that I need to be able to include nested fields for a couple of attributes on each Inventory (:case_price and :case_ship_price). I had previously done this in a very roundabout way using a has_many through association and storing those attributes on the pivot table, but it involved some hacky code to capture the field inputs from params and then save them through this block:
class CasesController < ApplicationController
def create
#case = Case.new(params[:case])
if #case.save
#case.case_lineitems.each do |li|
li.update_attributes(:price => params[:lineitem_price][li.inventory_id.to_s],
:shipping_cost => params[:lineitem_shipping][li.inventory_id.to_s])
end
redirect_to #case
else
render 'new'
end
end
end
This felt extremely clumsy and I was worried about problems it might cause, so I wanted to give a simple has_many, belongs_to relationship a try. However, I'm not sure if the typical <%= check_box_tag :inventory_ids, inventory.id, #case.inventories.include?(inventory), name: 'case[inventory_ids][]' %> works for that type of relationship. Here is what this section of my form looks like presently:
<table>
<thead>
<tr>
<th></th>
<th>Product</th>
<th>Serial #</th>
<th>Price</th>
<th>Shipping</th>
</tr>
</thead>
<tbody>
<% #inventories.each do |inventory| %>
<tr>
<td>
<%= check_box_tag :inventory_ids, inventory.id, #case.inventories.include?(inventory), name: 'case[inventory_ids][]' %>
</td>
<td><%= inventory.product.name %></td>
<td><%= inventory.serial_num %></td>
<%= f.fields_for :inventories, inventory do |inv| %>
<td>
<%= inv.text_field :case_price %>
</td>
<td>
<%= inv.text_field :case_ship_price %>
</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
This results in the first checkbox defaulting to checked, and if I leave all unchecked, all of the inventories become associated upon submission. Checking only a subset results in an exception along the lines of Couldn't find Inventory with ID=206 for Case with ID=. Finally, checking all of the Inventories seems to result in the associations and nested attributes saving correctly.
How do I clean this up so that it works as desired? And if I need to go back to a has_many through relationship, is there a better way to save attributes on the pivot table on the same form that creates the row on pivot table? I'd really appreciate any help with this, as no amount of searching has gotten me out of this challenge.

Resources