how to query in view ruby on rails - ruby-on-rails-3

i have this in the controller
#ads = Ad.all(:joins => 'LEFT JOIN states ON ads.state_id = states.id')
but i have problem to query field of states table.
any idea?
<% #ads.each do |ad| %>
<tr>
<td><%= ad.title %></td> <- title is ad field.no problem
<td><%= ad.name %></td> <- name is states field.problem at here
</tr>
<% end %>

I don't think this will work unless you have associations set up. Unless performance is a concern, you may just want to use the association without joins
ad.rb
class Ad < ActiveRecord::Base
belongs_to :state
end
state.rb
class State < ActiveRecord::Base
has_many :ads
end
controller
#ads = Ad.all
view
<% #ads.each do |ad| %>
<tr>
<td><%= ad.title %></td>
<td>
<%= ad.state.name %>
</td>
</tr>
<% end %>

I think you need to put this: ads.state_id = states.id like this: #{ads.state_id = states.id}
The #{ } will evaluate the ruby code inside. Otherwise what you have is just text inside a string.
I'm not quite sure what your issue is, though, so I'm not totally sure that will fix it.

Related

How to use index action of controller of a model that belongs to another model?

I'm coding a rails application to handle scheduling for university classes. Currently, I'm trying to make an index page to show all of the sections in the database, but I'm getting this error:
No route matches {:action=>"index", :controller=>"sections"}
However, when I look at my routes, I can see a controller action pair for section and index.
bin/rails routes
Prefix Verb URI Pattern Controller#Action
home_index GET /home/index(.:format) home#index
course_sections GET /courses/:course_id/sections(.:format) sections#index
POST /courses/:course_id/sections(.:format) sections#create
new_course_section GET /courses/:course_id/sections/new(.:format) sections#new
edit_course_section GET /courses/:course_id/sections/:id/edit(.:format) sections#edit
course_section GET /courses/:course_id/sections/:id(.:format) sections#show
PATCH /courses/:course_id/sections/:id(.:format) sections#update
PUT /courses/:course_id/sections/:id(.:format) sections#update
DELETE /courses/:course_id/sections/:id(.:format) sections#destroy
courses GET /courses(.:format) courses#index
POST /courses(.:format) courses#create
new_course GET /courses/new(.:format) courses#new
edit_course GET /courses/:id/edit(.:format) courses#edit
course GET /courses/:id(.:format) courses#show
PATCH /courses/:id(.:format) courses#update
PUT /courses/:id(.:format) courses#update
DELETE /courses/:id(.:format) courses#destroy
students GET /students(.:format) students#index
POST /students(.:format) students#create
new_student GET /students/new(.:format) students#new
edit_student GET /students/:id/edit(.:format) students#edit
student GET /students/:id(.:format) students#show
PATCH /students/:id(.:format) students#update
PUT /students/:id(.:format) students#update
DELETE /students/:id(.:format) students#destroy
root GET / home#index
rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show
rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
Why does it not route correctly?
My section controller looks like this:
class SectionsController < ApplicationController
def index
#courses = Course.all
end
def create
#course = Course.find(params[:course_id])
#section = #course.sections.create(section_params)
end
def update
#course = Course.find(params[:course_id])
#section = #course.sections.find(params[:id])
#section.update(section_params)
end
def destroy
#course = Course.find(params[:course_id])
#section = #course.sections.find(params[:id])
#section.destroy
end
private
def section_params
params.require(:section).permit(:section_letter, :section_professor, :section_meetings, :section_capacity)
end
end
My index.html.erb view in the sections folder looks like this:
<h2>Sections</h2>
<table>
<tr>
<th>Number</th>
<th>Section</th>
<th>Name</th>
<th>Credit Hours</th>
<th>Professor</th>
<th>Meetings</th>
<th>Capacity</th>
</tr>
<% #courses.each do |course| %>
<% course.sections.each do |section| %>
<tr>
<td><%= course.course_num %></td>
<td><%= section.section_letter %></td>
<td><%= course.course_name %></td>
<td><%= course.course_credits %></td>
<td><%= section.section_professor %></td>
<td><%= section.section_meetings %></td>
<td><%= section.section_capacity %></td>
</tr>
<% end %>
<% end %>
</table>
And my routes file looks like:
Rails.application.routes.draw do
get 'home/index'
resources :courses do
resources :sections
end
resources :students
root 'home#index'
end
Any help is appreciated!
Its because the sections controller is a nested resource under the courses resource. There is a sections#index but it takes a :course_id parameter.
In other words there is no /sections path that directly maps to sections#index
If its a one-off endpoint you can declare this route
get 'sections' => 'sections#index', as: :sections
And you'd then need to update the #index method in the SectionsController and just pull all Sections like
#sections = Section.all

Rails: more efficient way to export many-to-many tables to excel

I have the following models:
class Student
attr_accessible :name
has_many :courses, through: :course_students
has_many :course_students
end
class Course
attr_accessible :name
has_many :students, through: :course_students
has_many :course_students
end
class CourseStudent
attr_accessible :grade
belongs_to :course
belongs_to :student
end
Now, I'm trying to generate an excel table, with students as rows, and courses as columns, and the intersection will show the student's grade in that course.
So far I was handling small groups of students, so the following algorithm was ok:
<table>
...
<tbody>
<% #students..includes(:courses)each do |student| %>
<tr>
...
<% student.courses.includes(:course_students).each do |course| %>
<td><%= course.course_students.find_by_student_id(student.id).try(:grade) || '-' %></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
As you see, I've been trying to include the courses and the course_students when I load the data, but I still get a ton of queries. I know this is a classic N+1 queries issue (more like NxM+N+M+1), but the usual approach doesn't work.
I was hoping to pull all the data I need in fewer queries. Anybody got an idea?
Firstly, you should collect all courses to some standardized sort order (I'm using name arbitrarily, but it can be anything):
<% #courses = Course.order(:name) %>
You should also generate a header row to display the course columns:
<tr>
...
<% #courses.each do |course| %>
<td><%= course.name %></td>
<% end %>
</tr>
Now, you'll need to iterate over each student (eager-loading the :course_student join models to avoid N+1)
<% #students.includes(:course_students).each do |student| %>
<tr>
...
<% #courses.each do |course| %>
<td><%= student.course_students.detect do |cs|
cs.course_id == course.id
end.try(:grade) || '-' %></td>
<% end %>
</tr>
<% end %>
You can optimize this a bit more by avoiding the call to detect and building a grades hash for each student:
...
<% grades = student.course_students.each_with_object(Hash.new('-')) do |cs, hash|
hash[cs.course_id] = cs.grade
end %>
<% #courses.each do |course| %>
<td><%= grades[course.id] %></td>
<% end %>
...

Tidiest way of highlighting record if older than X days?

What is the tidiest DRY way in a Rails 3 application of highlighting a table row depending on its age?
<% #faults_open.each do |fault| %>
<tr>
<td><%= fault.name %></td>
<td><%= fault.faulttype %></td>
<td><%= fault.priority %></td>
<td><%= time_ago_in_words(fault.created_at) %> ago</td>
<td><%= link_to 'Show', fault %></td>
</tr>
<% end %>
I would like a class applied to the table row with an indication of its age which I can then style using CSS.
<% #faults_open.each do |fault| %>
<tr <% if fault.created_at > Date.1.week.ago %>class="weekold"<% end %>>
<td><%= fault.name %></td>
<td><%= fault.faulttype %></td>
<td><%= fault.priority %></td>
<td><%= time_ago_in_words(fault.created_at) %> ago</td>
<td><%= link_to 'Show', fault %></td>
</tr>
<% end %>
Something like the above but obviously adding them to the view would be messy. I plan on adding a couple of ages, such as:
weekold
twoweeksold
monthold
sixmonthold
yearold
ancient
I imagine a helper is the tidiest way, but I'm unsure on how the helper would work. Any pointers would be appreciated.
I recently did something similar, adding a class name to the row that corresponded to it's approximate age in weeks, then I used CSS to do the actual highlighting.
Why not use a helper.. (just an example)
def highlight_age_class (created_at)
##today ||= Date.today
num_weeks = ((##today - created_at.to_date) / 7).floor
class_name = "aged_#{num_weeks}_weeks"
num_weeks == 1 ? class_name.singularize : class_name
end
With your HTML..
<tr class="<%= highlight_age_class fault.created_at %>">
Combined with some CSS..
.aged_1_week
.aged_1_weeks
.aged_4_weeks
.aged_24_weeks
.aged_56_weeks
etc
You can then focus on extending and optimizing your helper method for age highlighting.

output belongs_and_has_many value in show action

I have the following code but can't render color as expected. When I render item.color I get #<Color:0x007ffce487a648>for example. If I render item.color.map(&:name) I get undefined method map for #<Color:0x007ffce6616918>
<% #this_week_orders.each do |order| %>
<tr style="font-weight:bold;">
<td><%= link_to "Order #{order.id}", order_path(order) %></td>
<td><%= l order.date, :format => :long %></td>
<td><%= pluralize(order.items.count, "item") %></td>
<td><%= number_to_currency(order.total_price) %></td>
<tr>
<% for item in order.items %>
<tr>
<td><li><%= item.product.name %></li></td>
<td><%= item.color %></td>
</tr>
<% end %>
<% end %>
Order has_many :items
Item belongs_to :order
Item belongs_to :product
Item belongs_to :color
scope :this_week, lambda { where("date > ?", 7.days.ago) }
Order controller
def this_week
#this_week_orders = Order.this_week.all
respond_to do |format|
format.html # index.html.erb
end
end
#<Color:0x007ffce487a648> reperesents an object of class Color (not a collection of color objects, whereupon it would make sense to use map). If Color has a name attribute, just write <%= item.color.name %>.
map is for use on an Array. item.color only returns one object. Use:
<%= item.color.name %>
if Color is a class like it appears to be you need to set the color value:
Something like:
<%= item.color.name %>
or whatever your value for the color is.

Why is Rails displaying memory addresses on my page?

My view:
<h1><%= #territory.name %></h1>
<%= link_to 'List of Territories', territories_path %>
<%= render 'shared/address_form' %>
<table>
<tr>
<td><strong>Name</strong></td>
<td><strong>Street</strong></td>
<td><strong>District</strong></td>
<td><strong>Note</strong></td>
<tr>
<%= #addresses.each do |address| %>
<tr>
<td><%= address.name %></td>
<td><%= address.street %></td>
<td><%= address.district %></td>
<td><%= address.note %></td>
</tr>
<% end %>
</table>
The form I render here is:
<%= form_for [#territory, #new_address] do |f| %>
<div>
<p>
<%= f.label :address %><br />
<%= f.text_area :address %>
</p>
</div>
<div class='file-wrapper'>
<%= f.submit "Submit" %>
</div>
<% end %>
Here is the territories controller, where the instance variable addresses is defined:
class TerritoriesController < ApplicationController
def index
#territories = Territory.all
end
def show
#territory = Territory.find(params[:id])
#new_address = #territory.addresses.build
#addresses = #territory.addresses
end
.
.
.
Why is Rails displaying
#<Address:0x7e088224>#<Address:0x7e0881d4>#<Address:0x7e088134>#<Address:0x7e088094># <Address:0x7e087ff4>#<Address:0x7e087f54>#<Address:0x7e087eb4>#<Address:0x7e087e14>#<Address:0x7e087d74>#<Address:0x7e0bce48>
after the form and before the table?
Thanks
Thomas
Check your layouts (app/views/layouts/*). Most likely you have included some ERB code in the one that is being rendered with this page that displays these addresses. Is that the full code of your view?
Edit: I found your solution. Right now, you have <%= #addresses.each ... %>. The each method runs the block on all elements, and then returns the list of elements. You do not want this code to be displayed. Remove the = so that <%= is just <%
You have some view code somewhere (in a layout or a view helper) that is implicitly calling the to_s method of your Address model instances. Look for something like <%= #address %>.
As you have seen, the non-overridden behaviour of the to_s method is to output the memory address of the object instance.
Those are not memory addresses. Those are instances of your Address class. If you'd override the to_s method in that class, you'd see that output there instead. And the reason you see those object printed out is your use of <%=. Changing this line
<%= #addresses.each do |address| %>
to this
<% #addresses.each do |address| %>
should fix it.
First: I can see no form in your view.
Second: Your view looks ok.
Have a look at your layout files.