I'm developing an app where an admin can see a group of users in HTML tables that are filtered by ":platoon => A,B,C,D"
All users are stored in a "users model" and I'm trying to have multiple HTML tables on one page showing only the users associated to that platoon.
UsersController:
class UsersController < ApplicationController
def index
#users = User.all
#a_platoon = #users.where(:platoon => #A)
#b_platoon = #users.where(:platoon => #B)
#c_platoon = #users.where(:platoon => #C)
#d_platoon = #users.where(:platoon => #D)
end
end
and in my index.html.erb:
<thead>
<tr>
<th>Name</th>
<th>Reg Number</th>
<th>Phone</th>
<th>Alt Phone</th>
<th colspan="7"></th>
</tr>
</thead>
<tbody>
<% #b_platoon.each do |b_platoon| %>
<tr>
<td><%= b_platoon.name %></td>
<td><%= b_platoon.reg_number %></td>
<td><%= b_platoon.phone %></td>
<td><%= b_platoon.alt_phone %></td>
</tr>
<% end %>
</tbody>
The goal here is to display all the users associated with b_platoon.
I'm not getting any errors, but my table just displays blank. I believe my problem lies in the controller methods but I'm not skilled enough to find it and I struggled with finding helpful documentation.
If it may help, heres my schema for my "Users" model:
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.integer "reg_number"
t.string "platoon"
t.string "phone"
t.string "alt_phone"
t.boolean "admin", default: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
Use b_platoon.your_field instead user.your_field
<% #b_platoon.each do |b_platoon| %>
<tr>
<td><%= b_platoon.name %></td>
<td><%= b_platoon.reg_number %></td>
<td><%= b_platoon.phone %></td>
<td><%= b_platoon.alt_phone %></td>
</tr>
<% end %>
You must call methods on enumerator in a .each
Related
I have three models, directors, movies, and ratings. These are their relations: A director has_many movies, a movie belongs_to a director, a movie has_many ratings and a rating belongs_to a movie.
My schema.rb:
ActiveRecord::Schema.define(version: 2022_01_20_101906) do
create_table "directors", force: :cascade do |t|
t.string "first_name"
t.date "date_of_birth"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "movies", force: :cascade do |t|
t.string "name"
t.date "release_date"
t.string "description"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "director_id"
t.index ["director_id"], name: "index_movies_on_director_id"
end
create_table "ratings", force: :cascade do |t|
t.integer "value"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "movie_id"
t.index ["movie_id"], name: "index_ratings_on_movie_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at", precision: 6
t.datetime "remember_created_at", precision: 6
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "movies", "directors"
add_foreign_key "ratings", "movies"
end
I'm currently trying to display a director's best-rated movie to display on a _director.html.erb patrial, so I tried this code to get the highest-rated movie value:
<% array = [] %>
<% rat_val = 0 %>
<% result = 0 %>
<% director.movies.each do |movie| %>
<% if movie.ratings.count > 0 %>
<% director.movies.each do |movie| %>
<% rat_val = number_with_precision(movie.ratings.average(:value), precision: 2) %>
<% array << rat_val %>
<% result = array.max %>
<% end %>
<%= result %>
<% break %>
<% end %>
<% end %>
But I'm struggling with what to do next to use this value to get the director's best-rated movie name to display.
One way to obtain the best-rated movie from each director would be selecting the average rating values for each director movie, ordering by that calculation and limiting the rows returned to 1.
This would be very complex to achieve in ActiveRecord. Having the whole select statement to get the movie_name as a string, so here's just the SQL version:
SELECT
d.*,
(
SELECT t.name
FROM (
SELECT name, (SELECT AVG(value) FROM ratings WHERE movie_id = movies.id) avgval
FROM movies
WHERE director_id = d.id
ORDER BY avgval DESC
LIMIT 1
) t
) movie_name
FROM directors d;
With this you don't need to manually iterate and counting raitings, you have every director column accessible plus the movie_name.
A better performing alternative to a subquery is to use a lateral join:
SELECT "directors".*,
"best_rated"."average_rating" AS rating
FROM "directors"
JOIN LATERAL (
SELECT AVG("ratings"."value") AS average_rating
FROM "movies"
INNER JOIN "ratings" ON "ratings"."movie_id" = "movies"."id"
WHERE "movies"."director_id" = "directors"."id"
GROUP BY "movies"."id"
ORDER BY "average_rating" DESC LIMIT 1
) best_rated ON true
This is somewhat like a foreach loop that selects a single row off the movies table which you can reference in the select clause. Writing the query with Arel/ActiveRecord is actually almost longer then the SQL string but is somewhat more portable.
class Director < ApplicationRecord
has_many :movies
has_many :ratings, through: :movies
# Select directors and the average ranking of their top ranking movie
def self.with_top_rated_movie
# this is the subquery for the lateral join
lateral = Movie
.select(
Rating.arel_table[:value].average.as('average_rating')
# You can add any additional columns you want from the movie here
)
.joins(:ratings)
.group(:id)
.order(average_rating: :desc)
# WHERE movies.director_id = directors.id This is our lateral reference
.where(Movie.arel_table[:director_id].eq(arel_table[:id]))
.limit(1)
# This is the alias used by the lateral join
best_rated = Movie.arel_table.alias('best_rated')
select(
arel_table[Arel.star],
best_rated[:average_rating].as('rating')
# You can add any additional columns you want from the movie here
).joins(
"JOIN LATERAL (#{lateral.to_sql}) best_rated ON true"
)
end
end
I managed to get it to work via this perhaps over-complicated loop:
<% ratings_all = [] %>
<% ratings_array = [] %>
<% rating_avg = [] %>
<% movies_rating = [] %>
<% best_rating = 0 %>
<% director.movies.each do |movie| %>
<% if movie.ratings.count > 0 %>
<% director.movies.each do |movie| %>
<% ratings_all = movie.ratings.to_a %>
<% ratings_array = ratings_all.map { |v| v[:value] } %>
<% ratings_avg = (ratings_array.sum.to_f / ratings_array.count).round(2).to_f %>
<% movies_rating << ratings_avg %>
<% best_rating = movies_rating.max %>
<% end %>
<% if movie.ratings.average(:value).round(2) == best_rating %>
<%= link_to movie.name, movie_path(movie) %>
(<%= best_rating %>/5.0)
<% end %>
<% end %>
<% end %>
but now it displays the name of the best rated movie on a directors and its rating, which is what I aimed to achieve.
I think the following would be clean, and sticks with using ActiveRecord:
director.movies.order(rating: :desc).first
I'm working on doing a simple joined search within a rails project. What I want to do is find a description of an item based on what the user enters in a search box. The error that I'm most commonly getting is:
Mysql2::Error: Unknown column 'item.description' in 'where clause': SELECT item_instances.* FROM item_instances INNER JOIN items ON items.id = item_instances.item_id WHERE item.description = 'server'
The search.html.erb page looks like the following:
<p>
Search results base on database field <span class='bold'><%= #columnType %></span>
with value: <span class='bold'><%= #search_value %> </span>
</p>
<p>Total Report Cost: <span class='bold'>$<%= #cost %><span></p>
<table class='reportTable'>
<thead>
<tr>
<th class='reportTableHeaderCell'>Inv number</th>
<th class='reportTableHeaderCell'>Description</th>
<th class='reportTableHeaderCell'>Serial</th>
<th class='reportTableHeaderCell'>PO number</th>
<th class='reportTableHeaderCell'>PO date</th>
<th class='reportTableHeaderCell'>Invoice</th>
<th class='reportTableHeaderCell'>Date Out</th>
<th class='reportTableHeaderCell'>Cost</th>
<th class='reportTableHeaderCell'>Acro</th>
</tr>
</thead>
<tbody>
<% #item_instances.each do |item_instance| %>
<tr class='searchTableRow'>
<td class='reportTableCell'><%= link_to item_instance.inv_number, edit_item_instance_path(item_instance) %></td>
<td class='reportTableCell'><%= item_instance.item.description %></td>
<td class='reportTableCell'><%= item_instance.serial %></td>
<td class='reportTableCell'><%= item_instance.po_number %></td>
<td class='reportTableCell'><%= item_instance.po_date %></td>
<td class='reportTableCell'><%= item_instance.invoice %></td>
<td class='reportTableCell'><%= item_instance.date_out %></td>
<td class='reportTableCell'><%= item_instance.cost %></td>
<td class='reportTableCell'><%= item_instance.acro %></td>
</tr>
<% end %>
</tbody>
</table>
item_instances.rb (model) file
class ItemInstance < ApplicationRecord
validates :inv_number, :serial, :cost, presence: true
belongs_to :item
scope :in_order, ->{order(:description)}
# Named Scopes
scope :search_for_records_by_date, ->(startDate, endDate) { where(date_out: startDate..endDate) }
scope :search_for_records_by_column_and_value, ->(columnName, value) { where("#{columnName}": "#{value}") }
#I know something may be wrong in here.
scope :search_for_records_by_column_and_value_item_table, ->(columnName, value) { where(item: "#{columnName}": "#{value}") }
end
The items model:
class Item < ApplicationRecord
validates :description, :cost, :list_price, presence: true
has_many :item_instances, dependent: :delete_all
scope :in_order, ->{order(:description)}
scope :search_for_active_items, ->(active) { where(active: active) }
scope :search_for_records_by_column_and_value_on_items, ->(columnName, value) { where("#{columnName}": "#{value}") }
end
The item_instances Controller:
class ItemInstancesController < ApplicationController
def search
# Getting the params from what the user submitted
#columnType = params[:columnType]
#search_value = params[:search_value]
if #columnType == 'description'
# SIMPLE THINGS I've TRIED:
# #item_instances = ItemInstance.joins(:item).where(item: {description: "server"})
##item_instances = ItemInstance.joins(:items)
#I TRIED THIS JUST TO SEE IF I COULD GET ANYTHING
#item_instances = ItemInstance.joins(:item).where(:item => {description: "server"})
##item_instances = ItemInstance.joins(:item).search_for_records_by_column_and_value_item_table(#columnType, #search_value)
end
respond_to do |format|
format.html { render :search }
end
end
end
The Routes file:
Rails.application.routes.draw do
resources :item_instances
get '/report', to: 'item_instances#report'
get '/search', to: 'item_instances#search'
resources :items
get '/active', to: 'items#active'
# Route to the home page
root 'item_instances#home'
end
schema.rb File:
ActiveRecord::Schema.define(version: 2020_08_17_190727) do
create_table "item_instances", options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.integer "inv_number"
t.string "serial"
t.integer "po_number"
t.date "po_date"
t.date "invoice"
t.date "date_out"
t.decimal "cost", precision: 8, scale: 2
t.string "acro"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "item_id"
t.index ["item_id"], name: "fk_rails_6ea33fd9d0"
end
create_table "items", options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.string "description"
t.decimal "cost", precision: 8, scale: 2
t.decimal "list_price", precision: 8, scale: 2
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "active"
end
add_foreign_key "item_instances", "items"
end
Please let me know if anything else is needed. I've looked through multiple articles and stackoverflow posts with no luck. Anything that can help will be appreciated.
In your item_instances_controller.rb, replace item with items in where condition. While where condition you must specify complete table name for comparison.
class ItemInstancesController < ApplicationController
def search
#yourcode
#item_instances = ItemInstance.joins(:item).where(:items => {description: "server"})
#yourcode
end
end
UPDATED
The official docs for this are not the best and a little confusing. I am gathering options from a feedback table and rendering them in a dropdown on a form and then saving them in a table called "answers" and column called "feedback_request" using collection_select:
<%= f.collection_select :feedback_request, Feedback.order(:feedback_option), :id, :feedback_request, {prompt: "Feedback"}, {class: "select large-1 behaviourForm"} %>
Answers table:
create_table "answers", force: :cascade do |t|
t.integer "user_id", limit: 4
t.string "subject", limit: 4
t.string "source", limit: 45
t.text "description", limit: 65535
t.string "significance", limit: 45
t.string "feedback_request"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "answers", ["feedback_request"], name: "feedback_index"
add_index "answers", ["significance"], name: "signif_index"
add_index "answers", ["source"], name: "source_index"
add_index "answers", ["subject"], name: "FK_HOM_MOD_idx"
add_index "answers", ["user_id"], name: "teacher_answer_index"
Feedback table
create_table "feedback", force: :cascade do |t|
t.string "feedback_option", limit: 45
end
Relationships
feedback.rb
class Feedback < ActiveRecord::Base
self.table_name = 'feedback'
has_many :answers, :class_name => 'Answer'
end
answer.rb
belongs_to :feedback, :class_name => 'Feedback', :foreign_key => :feedback_request
Table (as requested):
<thead>
<tr>
<% if current_user.teacher? %>
<th style="width:5%;", bgcolor="#313E4E" ></th>
<th bgcolor="#313E4E"><font color="#FFFFFF">Answer Title</font></th>
<% else %>
<th bgcolor="#313E4E"><font color="#FFFFFF">Subject</font></th>
<% end %>
<th bgcolor="#313E4E"><font color="#FFFFFF">Source</font></th>
<th bgcolor="#313E4E"><font color="#FFFFFF"><%= sort_link(#q, :created_at, "Assigned/Scheduled") %></font></th>
<th bgcolor="#313E4E"><font color="#FFFFFF"><%= sort_link(#q, :Due, "Due") %></font></th>
</tr>
</thead>
<tfoot>
</tfoot>
<%= form_tag destroy_multiple_answers_path, method: :delete do %>
<% #answers.each do |answer| %>
<tbody>
<tr>
<% if current_user.teacher? %>
<td><%= check_box_tag "answer[id][]", answer.id, class: "narrowtr" %></input></td>
<td height="1"><font color="#000000"><%= link_to answer.subject, answer, class: "blackLink" %></font></td>
<% else %>
<td height="1"><%= answer.subject %></td>
<% end %>
<td height="1"></td>
<td height="1"><%= answer.created_at %></td>
<td height="1"><%= answer.Due %></td>
</tr>
</tbody>
<% end %>
</table>
This gives me the following error on submit:
**undefined method `feedback_request' for #<Feedback id: 1, feedback_option: "Curriculum Management">**
Any guidance much appreciated.
I am debugging a rails app for my boss while he is on vacation. We have an app the company uses that we can use to fill out timesheets and view customer tickets. On the open tickets page, there is a column with a brief description of the ticket. We have an environment on Ubuntu for production, and an XP environment for development, both of those don't experience the bug. But if I run the environment on Windows 7 or newer, the description doesn't show up as a string but as a BigDecimal, usually as "0.0" some of the tickets show other numbers. I would post screenshots but I won't for the privacy of the company.
Here's what I know so far: The database we are using displays the actual description in the table. The view and controller are both explicitly converting to string, when I got rid of .to_s in the code, the bug persisted. I have the class type being sent to a logfile as well that confirms it is a BigDecimal. When running the production code from my machine the bug persisted. I think it is an OS compatibility issue possibly. Or somewhere between the database and the app itself, the data is being converted to BigDecimal in a file that I don't yet know about. I am running rails 3.0.7 and ruby 1.9.2p290
Here is the code I think is suspect:
<div id="page_center">
<div id="branding_row">
<%= label_tag("Show_Open", "Show Open Tickets",{:class => 'page_label'}) -%>
</div>
<div id="tabs">
<ul>
<% #locationHash.keys.each do |keyItem| %>
<li><%= keyItem %></li>
<% end %>
</ul>
<% #locationHash.keys.each do |keyItem| %>
<div id="tabs-<%= keyItem %>">
<table >
<tr >
<th style="width:50px; empty-cells:hide;">WO#</th>
<th style="width:125px; empty-cells:hide;">Customer Name</th>
<th style="width:125px; empty-cells:hide;">Description</th>
<th style="width:65px; empty-cells:hide;">Tech</th>
<th style="width:125px; empty-cells:hide;">Date/Time</th>
</tr>
<% #locationHash[keyItem].each do |ticketItem| %>
<tr>
<td><%= ticketItem.work_order.to_s %></td>
<td><%= ticketItem.customer_name.to_s %></td>
<td><%= ticketItem.woDesc.to_s %></td>
<td><%= ticketItem.tech.to_s %></td>
<td><%= ticketItem.created_at.to_s %></td>
</tr>
<% end %>
</table>
</div>
<% end %>
</div>
</div>
<div id="right_column">
</div>
Here's the controller:
class TicketsController < ApplicationController
def populate_workOrders
#customerId = params[:customerID]
logger.debug "#customerId = #{#customerId.to_s}"
#tickets = Ticket.where(:customer_id => #customerId)
logger.debug "#tickets size = #{#tickets.size.to_s}"
#outputTickets = Array.new
#tickets.each {|ticketItem|
#select only tickets with specific open/usable codes
if ['ARV','CAN','COM','D','H','O','S','PERM','CB','CN'].include?( ticketItem.woStatus )
logger.debug "workorder - #{ticketItem.work_order} status - #{ticketItem.woStatus}"
#outputTickets << ticketItem
end
}
respond_to do |format|
format.json { render :json => #outputTickets.to_json }
end
end
def show_open
logger.debug "****** inside Tickets - show_open ******"
#customersHash = Hash.new
#locationHash = Hash.new
#tempTicketArray = Array.new
# #customers = Customer.all
# logger.debug "#customers size = #{#customers.size.to_s}"
# #customers.each {|customerItem|
# #customersHash[customerItem.id] = customerItem
# }
## updates names
# #allTickets = Ticket.all
# #allTickets.each{|ticketItem|
# ticketItem.customer_name = #customersHash[ticketItem.customer_id].name
# ticketItem.save
# }
#tickets = Ticket.where(woStatus: ['ARV','CAN','COM','D','H','O','S'])
logger.debug "#tickets size = #{#tickets.size.to_s}"
#tickets.sort_by!{|y| [y.work_order]}.reverse!
#tickets.each {|ticketItem|
logger.debug "#{ticketItem.customer_name.to_s } + #{ticketItem.woDesc.class}"
if #locationHash.has_key?(ticketItem.office)
#locationHash[ticketItem.office] << ticketItem
else
#locationHash[ticketItem.office] = Array.new
#locationHash[ticketItem.office] << ticketItem
end
}
#locationHash.keys.each {|keyItem|
logger.debug "#{keyItem} array size = #{#locationHash[keyItem].size.to_s}"
#locationHash[keyItem].each{|ticketItem|
logger.debug "#{ticketItem.customer_name.to_s } - #{ticketItem.woDesc.class}"
}
}
end
end
Here is schema.rb with irrelevant parts ommitted:
create_table "customers", :force => true do |t|
t.string "number"
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "entries", :force => true do |t|
t.string "customer"
t.string "work_order"
t.text "description"
t.string "arrival_time"
t.string "depart_time"
t.integer "day_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "timesheet_order"
t.integer "user_id"
t.boolean "submitted"
t.integer "ticket_id"
t.integer "customer_id"
t.integer "type_id"
t.integer "productivityType"
end
create_table "ticket_import", :id => false, :force => true do |t|
t.string "srvStat"
t.string "offId"
t.string "callNbr"
t.string "custName"
t.string "priorityLevel"
t.string "svcDescr"
t.string "techId"
t.string "endDte"
t.string "custNum"
end
create_table "tickets", :force => true do |t|
t.string "work_order"
t.integer "customer_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "woStatus"
t.string "office"
t.text "woDesc"
t.string "tech"
t.string "entDate"
t.string "customer_name"
end
I receive error What happens??
Showing /Users/manu/Desktop/videocv/app/views/resumes/index.html.erb where line #16 raised:
SQLite3::SQLException: no such column: resumes.candidate_id: SELECT "resumes".* FROM "resumes" WHERE "resumes"."candidate_id" = ? LIMIT 1
Extracted source (around line #16):
13
14
15
16
17
18
19
<tbody>
<% #resumes.each do |resume| %>
<tr>
<td><%= current_candidate.resume.name %></td>
<td><%= current_candidate.resume.lastname %></td>
<td><%= current_candidate.resume.age %></td>
<td><%= link_to 'Show', resume %></td>
View
<h1>Listing resumes</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Lastname</th>
<th>Age</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #resumes.each do |resume| %>
<tr>
<td><%= current_candidate.resume.name %></td>
<td><%= current_candidate.resume.lastname %></td>
<td><%= current_candidate.resume.age %></td>
<td><%= link_to 'Show', resume %></td>
<td><%= link_to 'Edit', edit_resume_path(resume) %></td>
<td><%= link_to 'Destroy', resume, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Resume', new_resume_path %>
candidate.rb
class Candidate < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :resume
end
resume.rb
class Resume < ActiveRecord::Base
belongs_to :candidate
end
Database Schema
ActiveRecord::Schema.define(version: 20140825102626) do
create_table "candidates", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "resume_id"
end
add_index "candidates", ["email"], name: "index_candidates_on_email", unique: true
add_index "candidates", ["reset_password_token"], name: "index_candidates_on_reset_password_token", unique: true
add_index "candidates", ["resume_id"], name: "index_candidates_on_resume_id"
create_table "resumes", force: true do |t|
t.string "name"
t.string "lastname"
t.integer "age"
t.datetime "created_at"
t.datetime "updated_at"
end
end