I have the following code to display any comments that a user has made in a table on the users show page. The code works fine and a table is diplayed with all of the users comments and the permits they belong to. Currently the table displayed shows the permits in the order they were created by the user. I would like to arrange the table so that the permit column is displayed in alphabettical order instead of when they were created. Im not sure if I need to adjust this code or something in the controller.
<% if #user.comments.exists? then %>
<b>Comments:</b><br />
<table>
<tr>
<th>Permit</th>
<th>Comment</th>
</tr>
<% #user.comments.each do |comment| %>
<tr>
<td><%= link_to comment.permit.name, comment.permit %></td>
<td><%= comment.body %></td>
</tr>
<% end %>
</table>
<% end %>
Use the ActiveRecord order method.
Check the official documentation here: http://guides.rubyonrails.org/active_record_querying.html#ordering
In your case, that would be something like:
<% #user.comments.order('name').each do |comment| %>
> sorted_permits = #user.permits.sort
This gives you a list of permits, ordered naturally (i.e. if they are String values, they are sorted alphabetically, if they are numeric values, they are sorted from lowest to highest). You can do that in your view, or more typically, in your controller.
So, if I have a list of permits such as:
permits = ["Fishing", "Hunting", "Reading", "Driving"]
Then when I can do the following:
> permits.sort
=> ["Driving", "Fishing", "Hunting", "Reading"]
NOTE that .sort returns a copy of the list, in sorted order, while the similar .sort! modifies the original list, reordering it permanently (in memory), but does not change the order/IDs of the permits in the database.
See: http://www.ruby-doc.org/core/classes/Array.html#M000244
Using the :order option directly on the relation definition should do the trick:
class Comment < ActiveRecord::Base
has_many :permits, :order => 'name DESC'
end
Related
I have a model student with a subject and grade attribute. A student can have many subjects and grades, and what I'd like to do is be able to publish the 2nd or 3rd subject listed for a specific student.
For example, the user searches for a student, then clicks on the student, which brings them to a separate page listing information about that particular student (ie, student id:1). Is there code I can add to the view to list the nth item from the subject and grade attributes?
I looked online here and found similar questions, but those solutions related to the model, not the attributes. For example, one solution recommended using the limit method in the controller and another recommended using the following code:
<% firm.state_of_business.split(',').each_with_index do |state, index| %>
<td> <b>State <%= index + 1 %></b> <%= state %>
This seems to work well, when you don't have a specific model selected. When you select a particular model(ie, student id:1), this doesn't seem to work. At least not for me. Right now my code below is showing the first item. How might I get it to list subject 1 & grade 1, subject 2 & grade 2, subject 3 & grade 3, etc.. See sample code below. Please note, that I tried other solutions on here, but couldn't get them to work, which made me think that my problem might be different than the ones previously presented. Thanks for your help.
View Code
<h2>Students</h2>
<p> Student:
<%= #student.name %>
</p>
<table>
<tr>
<th> Subject </th>
<th> Grade </th>
</tr>
<tr>
<td><%= #student.subject %> </td>
<td><%= #student.grade %> </td>
<tr>
</table>
Controller Show Method
def show
#user = current_user
#student = Student.find(params[:id])
end
Desired Output
Student: Matt Jones
Subject Grade
Math 95
History 90
English 91
Try adding this code:
<%= #student.grade.split(',')[0] %>
The [0] will publish the first item in the array. [1] will publish the 2nd item, etc. That should work.
I guess you can just create another model called Subject and add has_many :subjects in class Student.
In class Subject, you can add this line belongs_to :student.
And then you can do this something like this:
<% #student.subjects.each do |subject| %>
<tr>
<td><%= subject.name %> </td>
<td><%= subject.grade %> </td>
<tr>
<% end %>
Just to make it clear, Subject model contains attribute name and grade in above example.
Basically I have a table output on a page, base view. The headers (milestones) are dynamically integrated by passing the Milestones class and iterating through each with an .each do. The table rows are then initially generated by doing the same thing, pulling in client, trade, and units, into the first three columns. The rest of the columns should be dates (class entry attribute due) that are calculated by a lookup of sorts using the client and trade attributes accessible by the loop, and the milestone ID accessible by an array created when dynamically generating them for the headers. This all works correctly as it should, and the table generates fine.. however the dates are output as #<Entry:0x000000056faa90> and so on.
Now I have come across this problem before, and basically the fix was to add a class definition and tell it to return what I assume to be the attribute of that instance. For example:
class Client < ActiveRecord::Base
validates :id, presence:true
validates :client, presence:true
def name
return self.client
end
end
And this works great, but only for how I access the client. Unfortunately I am accessing entry.due differently. Here are my relevant bits of code.
base_controller.rb
class BaseController < ApplicationController
def index
#trades = Trade.all
#milestones = Milestone.all
##entries = Entry.all #Didn't seem relevant to how I am trying to access the information.
end
end
entry.rb
class Entry < ActiveRecord::Base
belongs_to :client
belongs_to :trade
belongs_to :milestone
validates :client, presence:true
validates :trade, presence:true
validates :milestone, presence:true
validates :due, presence:true
# Some of my trial and error; all to no avail.
def due
return self.due
end
def self.due
return self.due
end
def pickDue(c,t,m)
ret = self.select("date_format(due, '%m/%d/%Y')").where("client_id=? AND trade_id=? AND milestone_id=?", c, t, m).first
return ret
end
end
base > index.html.erb
<table>
<thead>
<tr class="sort">
<th>Client</th>
<th>Trade</th>
<th>Units</th>
<%
ms = []
#milestones.each do |milestone|
ms.push(milestone)
%>
<th><%= milestone.name %></th>
<% end %>
</tr>
</thead>
<tbody>
<% #trades.order("entered").last(10).each do |trade| %>
<tr>
<td><%= trade.client.name %></td>
<td><%= trade.name %></td>
<td><%= trade.units %></td>
<% ms.each do |msr| %>
<td>
<%= Entry.select("date_format(due, '%m/%d/%Y')").where("client_id=? AND trade_id=? AND milestone_id=?", trade.client, trade, msr).first %>
<%#= Entry.pickDue(trade.client, trade, msr) %>
</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
With this approach, I can load the page error-free, but instead of showing dates, I am shown objects like #<Entry:0x000000056faa90>.
If I add .due to the end of the selector:
<%= Entry.select("date_format(due, '%m/%d/%Y')").where("client_id=? AND trade_id=? AND milestone_id=?", trade.client, trade, msr).first.due %>
# undefined method `due' for nil:NilClass
If I add .due after anything else:
<%= Entry.due.select("date_format(due, '%m/%d/%Y')").where("client_id=? AND trade_id=? AND milestone_id=?", trade.client, trade, msr).first %>
<%= Entry.select("date_format(due, '%m/%d/%Y')").due.where("client_id=? AND trade_id=? AND milestone_id=?", trade.client, trade, msr).first %>
<%= Entry.select("date_format(due, '%m/%d/%Y')").where("client_id=? AND trade_id=? AND milestone_id=?", trade.client, trade, msr).due.first %>
# stack level too deep
I have tried dozens of different methods acquired through several days of looking into this with no luck. Besides the current situation where it outputs objects instead of the object attribute, the next closest I've come I think is when I got an error saying it could not find the due method for an ActiveRecord object, but I don't remember how got to that error.
I would really appreciate any input.
If I understand correctly, I would get rid of that trial and error code in your model, and then in your view you can just call this:
Entry.where(client: trade.client, milestone: msr, trade: trade).pluck(:due)
This goes inside your milestone loop in your view, like this:
<% ms.each do |msr| %>
<td>
<%= Entry.where(client: trade.client, milestone: msr, trade: trade).pluck(:due).first %>
</td>
<% end %>
Pluck returns an array of values from the columns you specify (see the relevant section of the RailsGuide, so note that the .first method is the Array#first method, not the ActiveQuery#first method. You could even make a query that passes in all of the milestones at once instead of running a query for each milestone, thereby preventing an N+1 query situation.
That would be:
<% Entry.where(client: trade.client, trade: trade, milestone: ms).pluck(:due).each do |entry_due_date| %>
<td>
<%= entry_due_date %>
</td>
<% end %>
Lastly, while I gave you the code for the SQL query in the view, it is generally considered a bad practice in Rails to write SQL queries in your view, and you should probably make this into a method in your Entry model.
I think you might be looking for attributes method.
entry = Entry.new
entry.attributes #=> returns a hash of key-value attribute pairs
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.
This is hard to explain.
I have a form builder (Question model) that creates form fields that belong to a specific event, these questions appear on the registration page handled by the Registration model.
There are default form fields that always stays the same and then X additional ones created by the form builder. The Question model has the field "db_field", which gets populated with the corresponding db field in the Registration model.
Note that the questions also have position_ids.
What I'm trying to achieve is to get answers display under the corresponding headings in a table in the index page, my view looks like this
<% #questions = Question.where(:event_id => #event.id).order(:position) %>
<table class="table table-striped table-bordered table-condensed">
<tr>
<% #questions.each do |q| %>
<th><%= q.question %></th>
<% end %>
</tr>
<% #event.registrations.each do |r| %>
<tr>
<% #questions.each do |q| %>
<td><%= r.(q.db_field) %></td>
<% end %>
</td>
</table>
So basically I need 'q.db_field', which might be 'title', for instance, to call r.title - if that makes sense.
I've tried a few things, but nothing seems to work.
Thanks in advance,
Charl
You can use Object#send to invoke methods on a given object.
See http://ruby-doc.org/core-2.0/Object.html for more info.
so replacing <%= r.(q.db_field) %> with <%= r.send(q.db_field) %> will allow you to use the field name from the DB. If you need to specify arguments for the method being called, you can pass them in after the method name. Per the docs, method name can either be a symbol or a string, if it is a string, it will be converted to a symbol for you.
<% #blog.blog_comment_types.each do |blog_comment_type| %>
<tr>
<td><%= blog_comment_type.comment_type_id %></td>
<td>Comment name goes here</td>
</tr>
<% end %>
I want to be able to output the comment name based off the comment_type_id.
I an looping through the blog_comment_type table, I want to use the "comment_type_id" column so I can pull from the following table: comment_type which has the name field I want to output. The comment_type table has an id which is the referenced comment_type_id being looped through.
Is there a best practice in Rails to do so within a view?
Tbl: comment_type
fields:
id
name
tbl: blog_comment_type
fields:
id
comment_type_id (this is the matching id in the comment_type table).
Thanks!
In Rails and beyond, the best practice is not to do this in a view. Instead, if you setup your Blog object so it knows about the comment types associated with it, then the problem becomes pretty simple:
class Blog
has_many :blog_comment_types
....
end
then in your view:
<% #blog.blog_comment_types.each do |blog_comment_type| %>
<tr>
<td><%= blog_comment_type.id %></td>
<td><%= blog_comment_type.name %></td>
</tr>
<% end %>