Cannot access values from other models - ruby-on-rails

I am pretty new with Rails. What I am trying to do is access the branch name and product name of a sale. I assigned associations with the three models (Sale,Branch,Product). However, I am unable to retrieve values. In the 'index.html.erb' view, it displays a nil value for the branch name and product name. How can I access the values?
sale.rb
class Sale < ActiveRecord::Base
belongs_to :branch, :class_name => "Branch", :foreign_key => :branch_code
belongs_to :product, :class_name => "Product", :foreign_key => :product_sku
end
branch.rb
class Branch < ActiveRecord::Base
has_many :sales, :class_name => "Sale", :foreign_key => :branch_code
end
product.rb
class Product < ActiveRecord::Base
has_many :sales, :class_name => "Sale", :foreign_key => :product_sku
end
index.html.erb
<h1>Sales Index</h1>
<h2>Files in database</h2>
<table border=2>
<tr>
<th>Branch Name</th>
<th>Product Name</th>
<th>Qty. Sold</th>
<th>End of day Qty</th>
<th>Date</th>
<th>Date Created</th>
<th>Date Last Modified</th>
</tr>
<% #sales.each do |sale| %>
<tr>
<td><%= sale.branch %></td>
<td><%= sale.product %></td>
<td><%= sale.quantity_sold %></td>
<td><%= sale.end_of_day_quantity %></td>
<td><%= sale.salesdate %></td>
<td><%= sale.created_at %></td>
<td><%= sale.updated_at %></td>
</tr>
<% end %>
</table>
sales_controller.rb
class SalesController < ApplicationController
def index
#files = Dir.glob('/Users/xxyy/Documents/rails/Dummy/*.csv')
##mapper = Array.new()
require 'csv'
require 'fileUtils'
for file in #files
filename = File.basename(file, ".*")
date = filename[22..31]
csv_text = File.read(file)
CSV.foreach(file, :headers => true) do |row|
Sale.create(:branch_code => row[0], :product_sku => row[1], :quantity_sold => row[2], :end_of_day_quantity => row[3], :salesdate => date)
end
FileUtils.mv(file, '/Users/xxyy/Documents/rails/Read/')
end
#sales = Sale.all
end
end
schema.rb
ActiveRecord::Schema.define(version: 20140812013013) do
create_table "branches", force: true do |t|
t.string "branch_code"
t.string "branch_name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "products", force: true do |t|
t.string "product_sku"
t.string "product_name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "sales", force: true do |t|
t.string "branch_code"
t.string "product_sku"
t.integer "quantity_sold"
t.integer "end_of_day_quantity"
t.integer "branch_id"
t.integer "product_id"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "salesdate"
end
add_index "sales", ["branch_id"], name: "index_sales_on_branch_id"
add_index "sales", ["product_id"], name: "index_sales_on_product_id"
end

Make sure you have the associations done right.
class Product < ActiveRecord::Base
has_many :sales, :class_name => "Sale", :foreign_key => :product_sku
end

has_many :sales
This needs to be plural.
class Branch < ActiveRecord::Base
has_many :sales
end
You don't need to specify the class name here and the foreign key should be branch_id (I'm guessing) which also doesn't need to be specified.

Related

Ruby on rails: correct solution for many-to-many associations?

I'm new to ruby on rails and am trying to set up student grading system.
Each student has many courses.
Each course has many units.
Each students needs a grade for each unit.
Models
class Student < ApplicationRecord
validates :student_id, :name, :group, presence: true
has_many :student_classes
has_many :courses, through: :student_classes
has_many :units, through: :courses
has_many :units, through: :grades
has_many :grades
end
class StudentClass < ApplicationRecord
belongs_to :student
belongs_to :course
end
class Course < ApplicationRecord
has_many :student_classes
has_many :students, through: :student_classes
has_many :units
end
class Unit < ApplicationRecord
belongs_to :course
has_many :students, through: :grades
has_many :grades
end
class Grade < ApplicationRecord
belongs_to :student
belongs_to :unit
end
Migration
class CreateStudents < ActiveRecord::Migration[7.0]
def change
create_table :students do |t|
t.integer :uid
t.string :group
t.integer :student_id
t.string :name
t.string :first_name
t.string :middle_name
t.string :last_name
t.integer :phone
t.string :home_school
t.string :external_email
t.string :usi
t.datetime :dob
t.boolean :lnn_assessment_registered_status
t.boolean :lnn_assessment_completed_status
t.boolean :enrolment_paperwork_completed__status
t.datetime :enrolment_paperwork_completed_date
t.string :enrolled_in_energySpace_userid
t.boolean :teams_group_and_chat_created_and_user_added_status
t.string :Comments
t.datetime :date
t.string :assessor_name
t.string :campus
t.boolean :yes_no_status
t.string :satisfactory
t.string :competency
t.string :course_code
t.string :course_name
t.timestamps
end
class CreateStudentClasses < ActiveRecord::Migration[7.0]
def change
create_table :student_classes do |t|
t.references :student, null: false, foreign_key: true
t.references :course, null: false, foreign_key: true
t.timestamps
end
class CreateCourses < ActiveRecord::Migration[7.0]
def change
create_table :courses do |t|
t.string :course_name
t.string :course_code
t.timestamps
end
class CreateGrades < ActiveRecord::Migration[7.0]
def change
create_table :grades do |t|
t.references :student, null: false, foreign_key: true
t.references :unit, null: false, foreign_key: true
t.boolean :enrolled
t.boolean :cy
t.boolean :awaiting_confirmation
t.boolean :profiling
t.boolean :missed
t.boolean :skills
t.boolean :ukt
t.boolean :waiting_on_staff
t.timestamps
end
class CreateUnits < ActiveRecord::Migration[7.0]
def change
create_table :units do |t|
t.string :unit_name
t.string :unit_code
t.integer :course_id
t.timestamps
end
I am able to view the code with in the course model with
<h1><%= #course.course_name %></h1>
<table>
<tr >
<tr class="student-list-row">
<th>Unit Name</th>
<th>Unit Code</th>
<th>Unit ID</th>
<% #course.units.each do |unit| %>
<tr class="student-list-row">
<td class="student-list-item"><%= unit.unit_name %></td>
<td class="student-list-item"><%= unit.unit_code %></td>
<td class="student-list-item"><%= unit.id %></td>
<td><%= link_to 'Show' %></td>
</tr>
<% end %>
</tr>
</tr>
But I would like to create a table that has all units in a course as the columns, and the students as the rows, with each grade being shown. Is this possible to do with this arrangement?
Is this also able to be achieved whilst viewing all courses/units a student is assigned to?

Display Unique Results from Two Models

I have two models: games and pickems.
Here is my schema for these models:
create_table "games", force: :cascade do |t|
t.integer "week_id", limit: 4
t.integer "home_team_id", limit: 4
t.integer "away_team_id", limit: 4
t.integer "home_score", limit: 4
t.integer "away_score", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "season_id", limit: 4
end
create_table "pickems", force: :cascade do |t|
t.integer "user_id", limit: 4
t.integer "game_id", limit: 4
t.integer "winner_id", limit: 4
t.integer "score", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Game model:
class Game < ActiveRecord::Base
belongs_to :home_team, class_name: 'Team'
belongs_to :away_team, class_name: 'Team'
belongs_to :week
belongs_to :season
end
Pickem model:
class Pickem < ActiveRecord::Base
has_one :user
has_one :game
has_one :winner, class_name: 'Team'
end
In my view, I want to display all Games that do not have a Pickem associated that is referencing it. I also want to display below all the Pickems and the game attributes associated. What do I need to be calling from the controller and/or add to the model(s) to display this information?
You will need to correct the Games/Pickem association, by adding this to the Game model:
has_one :pickem
and this to the Pickem model:
belongs_to :game
This query will retrieve all of the Games that do not have a Pickem associated:
#games_without_pickems = Game.joins(:pickem).group("games.id").having("COUNT('pickems.id') = 0").order("games.id")
change table references
This will retrieve all of the Pickems and associated Games information:
#pickems = Pickem.includes(:games).all
In your view, simply loop over both #games_without_pickems and #pickems, like this:
<table>
<th>
<td>Week</td>
<td>Home Team</td>
<td>Away Team</td>
<td>Home Score</td>
<td>Away Score</td>
<td>Season</td>
</th>
<% #games_without_pickems.each do |game| %>
<tr>
<td><%= game.week.name %></td>
<td><%= game.home_team.name %></td>
<td><%= game.away_team.name %></td>
<td><%= game.home_score %></td>
<td><%= game.away_score %></td>
<td><%= game.season.name %></td>
</tr>
<% end %>
</table>
<table>
<th>
<td>User</td>
<td>Winner</td>
<td>Score</td>
<td>Week</td>
<td>Home Team</td>
<td>Away Team</td>
<td>Home Score</td>
<td>Away Score</td>
<td>Season</td>
</th>
<% #pickems.each do |pickem| %>
<tr>
<td><%= pickem.user.name %></td>
<td><%= pickem.winner.name %></td>
<td><%= pickem.score %></td>
<td><%= pickem.game.week.name %></td>
<td><%= pickem.game.home_team.name %></td>
<td><%= pickem.game.away_team.name %></td>
<td><%= pickem.game.home_score %></td>
<td><%= pickem.game.away_score %></td>
<td><%= pickem.game.season.name %></td>
</tr>
<% end %>
</table>
That should do it.
First of all, you have
# in `pickems` table
t.integer "game_id", limit: 4
and
# in Pickem Model
class Pickem < ActiveRecord::Base
...
has_one :game
...
end
I think for has_one belongs_to, you need to put foreign_key in games table rather than pickems table and it will start making sense.
i.e.
create_table "games", force: :cascade do |t|
...
t.integer "pickem_id", limit: 4
...
end
class Game < ActiveRecord::Base
...
belongs_to :pickem
...
end
Now
I want to display all Games that do not have a Pickem associated that
is referencing it
Game.where(pickem_id: nil)
One Suggestion
Since your Game model belongs to multiple models like Pickem, Team, etc. so you can use Polymorphic Association instead.
Reason: If one of your game record belongs to pickem then other fields will be empty.

Adding Tags in Rails

Adding Tags and I Get this ERROR:
SQLite3::SQLException: no such column: taggings.available_work_id:
SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" =
"taggings"."tag_id" WHERE "taggings"."available_work_id" = ?
Available_work.index.html
<tbody>
<% #available_works.each do |available_work| %>
<tr>
<td><%= available_work.title %></td>
<td><%= available_work.description.html_safe %></td>
<td>Tags: <%= raw available_work.tags.map(&:name).map { |t| link_to t, tag_path(t) }.join(', ') %></td>
<td><%= image_tag available_work.image_url(:thumb) %></td>
<td><%= link_to 'Show', available_work %></td>
<td><%= link_to 'Edit', edit_available_work_path(available_work) %></td>
<td><%= link_to 'Destroy', available_work, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
Available_work.rb
class AvailableWork < ActiveRecord::Base
attr_accessor :image, :remote_image_url, :tag_list
mount_uploader :image, ImageUploader
has_many :taggings
has_many :tags, through: :taggings
def self.tagged_with(name)
Tag.find_by_name!(name).available_work
end
def self.tag_counts
Tag.select("tags.*, count(taggings.tag_id) as count").
joins(:taggings).group("taggings.tag_id")
end
def tag_list
tags.map(&:name).join(", ")
end
def tag_list=(names)
self.tags = names.split(",").map do |n|
Tag.where(name: n.strip).first_or_create!
end
end
end
Tag.rb
class Tag < ActiveRecord::Base
has_many :taggings
has_many :available_work, through: :taggings
end
Taggings.rb
class Tagging < ActiveRecord::Base
belongs_to :tag
belongs_to :availble_work
end
Schema
create_table "available_works", force: :cascade do |t|
t.string "title"
t.string "description"
t.string "tags"
t.string "image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "taggings"
end
You would have to add an available_work_id column the to taggings table. It might be better however to create a polymorphic relation to the tagged object though so that you can use tags for more than the AvailableWork model.
EDITED. There where several mistakes in my example. Here is a complete running version:
class Tag < ActiveRecord::Base
has_many :taggings
def self.tag_counts
select("tags.*, count(taggings.tag_id) as count")
.joins(:taggings)
.group("taggings.tag_id")
end
end
class Tagging < ActiveRecord::Base
belongs_to :tag
belongs_to :tagged,
polymorphic: :true,
inverse_of: :taggings
end
class AvailableWork < ActiveRecord::Base
has_many :taggings, as: :tagged
has_many :tags, through: :taggings
def self.tagged_with(name)
# We have to do this in two queries since Rails does not
# do joins on polymorphic relations.
ids = Tagging.where(tagged_type: self.name)
.joins(:tag)
.where(tags: { name: name }).pluck(:tagged_id)
find(ids)
end
def self.tag_counts
Tag.tag_counts.where(taggings: { tagged_type: self.name })
end
def tag_list
tags.map(&:name).join(", ")
end
def tag_list=(names)
self.tags = names.split(",").map do |n|
Tag.where(name: n.strip).first_or_create!
end
end
end
ActiveRecord::Schema.define(version: 20150621234032) do
create_table "available_works", force: :cascade do |t|
t.string "title"
t.string "description"
t.string "image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "taggings", force: :cascade do |t|
t.integer "tag_id"
t.integer "tagged_id"
t.string "tagged_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id"
add_index "taggings", ["tagged_id"], name: "index_taggings_on_tagged_id"
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
<table>
<tbody>
<% #available_works.each do |available_work| %>
<tr>
<td><%= available_work.title %></td>
<td><%= available_work.description.try(:html_safe) %></td>
<td>Tags: <%= available_work.tag_list %></td>
<td><%#= image_tag available_work.image_url(:thumb) %></td>
<td><%= link_to 'Show', available_work %></td>
<td><%= link_to 'Edit', edit_available_work_path(available_work) %></td>
<td><%= link_to 'Destroy', available_work, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
Note that I commented out the images part to save time since it is not directly relevant to the question.
The Rails app I created to answer the question is available at https://github.com/maxcal/playground/tree/adding-tags-in-rails.

how to show genres through associatin in the song controller?

if you go to www.leapfm.com you'll see each song has a youtube url in parenthesis to the right of it. After gauging feedback I have decided to instead display the genre tags in the parenthesis.
When trying to do this,
I'm getting this error:
Couldn't find Genre without an ID
Extracted source:
def genre_name
#genre = Genre.find(params[:id])
end
def get_last_song
song_controller snippit
def index
if params[:query].present?
#songs = Song.search(params)
get_last_song
genre_name
elsif params[:genre]
#songs = Song.tagged_with(params[:genre]).paginate(:page => params[:page], :per_page => 15)
get_last_song
genre_name
else
#songs = Song.order('id').order('plusminus desc nulls last').paginate(:page => params[:page], :per_page => 15)
##songs = Song.tally.paginate(:page => params[:page], :per_page => 15)
get_last_song
genre_name
end
end
def genre_name
#genre = Genre.find(params[:id])
end
index.html.erb (_song partial) snippit
<div class="title">
<%=link_to image_tag('arrow.gif'), vote_for_song_path(song), :remote => true, :method => :put if controller.action_name == "index" %>
<%= link_to song.title, song %><span class="subtext"> (<%= song.genre_name %>)</span>
</div>
song.rb snippit:
class Song < ActiveRecord::Base
acts_as_voteable
belongs_to :user
has_many :comments, :dependent => :destroy
has_many :genre_songs
has_many :genres, through: :genre_songs
genre.rb
class Genre < ActiveRecord::Base
has_many :genre_songs, :dependent => :destroy
has_many :songs, through: :genre_songs
end
schema snippit
create_table "genre_songs", force: true do |t|
t.integer "genre_id"
t.integer "song_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "genre_songs", ["genre_id"], name: "index_genre_songs_on_genre_id", using: :btree
add_index "genre_songs", ["song_id"], name: "index_genre_songs_on_song_id", using: :btree
create_table "genres", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "songs", force: true do |t|
t.string "title"
t.string "artist"
t.text "url"
t.string "track_file_name"
t.string "track_content_type"
t.integer "track_file_size"
t.datetime "track_updated_at"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "plusminus"
end
You need to get rid off gendre_name method, as it doesn't give you what you want. You've assigned #songs to some list of songs, hence most likely somewhere in your view you have sth like:
<% #songs.each do |song| %>
# display song row
<% end %>
if so, use sth like below inside this each "loop":
(<%= song.genres.map(&:names).join(', ') %>)

Rails, has_many, belongs_to

Schema:
create_table "reports", :force => true do |t|
t.integer "user_id"
t.string "apparatus"
t.string "capt"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", :force => true do |t|
t.string "login", :limit => 40
t.string "name", :limit => 100, :default => ""
t.string "email", :limit => 100
t.string "crypted_password", :limit => 40
t.string "salt", :limit => 40
t.datetime "created_at"
t.datetime "updated_at"
t.string "remember_token", :limit => 40
t.datetime "remember_token_expires_at"
t.string "rank"
t.integer "shift"
t.integer "access"
end
user model:
Class User < ActiveRecord::Base
has_many :reports
# bunch of other stuff thats not important
end
report model:
Class Report < ActiveRecord::Base
belongs_to :user
end
views/reports/index
<% #reports.each do |report| %>
<tr>
<td><%= report.user_id %></td> # ****THIS IS THE LINE IN QUESTION****
<td><%= report.apparatus %></td>
<td><%= report.capt %></td>
<td><%= report.body %></td>
<td><%= link_to 'Show', report %></td>
<td><%= link_to 'Edit', edit_report_path(report) %></td>
<td><%= link_to 'Destroy', report, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
I would like to be able to display the name of the user that created the report. I was under the assumption that declaring the belongs_to and has_many associations would make this possible by writing report.user.name or something like that. Where have I gone wrong?
I'm 99% sure it's because one or more of your reports do not have an associated user. Try
<%= report.user.name rescue "none" %>
When there is no value in user_id field on a report then report.user will return nil. So report.user.name would be like calling nil.name, which raises an error.
UPDATE: here's a better way:
<%= report.user.try(:name) %>
You can do:
<%= report.user.name %>
But for efficiency, in your controller you can do a join to get the users name in the same query used to fetch #reports.
This query might look something like:
#reports = Report.select("reports.id as id, reports.apparatus as apparatus, reports.capt as capt, reports.body as body, users.name as user_name").joins("LEFT JOIN `users` ON `users`.`id` = `reports`.`user_id`")
Then your output would look like:
<%= report.user_name %>

Resources