Rails Active record association by instance methods - sql

I am trying to have (devise) users.rb be placed within a ClassInstruction.rb based on their userRole.rb (teacher or student). The models and schema are below, along with the error. It errors on the final .where statement, I have tried singular, pluralized, and other variations. I am basing this on my original post here, but am unable to get the example answer working.
Schema.rb :
ActiveRecord::Schema.define(:version => 20130523111519) do
create_table "class_instructions", :force => true do |t|
t.string "name"
t.datetime "time"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "class_instructions", ["user_id"], :name => "index_class_instructions_on_user_id"
create_table "roles", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "songs", :force => true do |t|
t.string "title"
t.string "content"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "user_id"
t.string "fractionRepresentation"
t.string "measureRepresentation"
end
create_table "user_roles", :force => true do |t|
t.integer "user_id"
t.integer "role_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "user_roles", ["role_id"], :name => "index_user_roles_on_role_id"
add_index "user_roles", ["user_id"], :name => "index_user_roles_on_user_id"
create_table "users", :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
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
end
User.rb model :
class User < ActiveRecord::Base
#DEVISE STUFF
#== Associations
has_many :user_roles, :dependent => :destroy
has_many :roles, :through => :user_roles
has_many :songs
#== Instance Methods
def thisUsersID
self.id
end
def student_classes(class_instruction_name)
member_classes(class_instruction_name, 'Student')
end
def teacher_classes(class_instruction_name)
member_classes(class_instruction_name, Role::TEACHER)
end
private
def member_classes(class_instruction_name, type)
ClassInstruction \
.joins(:user_role) \
.where(["user_role.user_id = ?", id]) \
.joins("INNER JOIN roles ON roles.id = user_roles.role_id") \
.where("roles.name = ?", type) \
.where("class_instruction.name = ?", class_instruction_name)
end
end
user_role.rb model:
class UserRole < ActiveRecord::Base
belongs_to :user
belongs_to :role
has_many :class_instructions, :dependent => :destroy
end
role.rb model
class Role < ActiveRecord::Base
has_many :user_roles, :dependent => :destroy
end
class_instruction.rb model (names are 'ss' and'math-101')
class ClassInstruction < ActiveRecord::Base
belongs_to :user_role
end
Error Stack (from the ruby console after getting the first student and trying to find its classInstruction):
Loading development environment (Rails 3.2.2)
1.9.3-p429 :001 > U = User.find(3)
User Load (3.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 3]]
=> #<User id: 3, email: "stu#test.org", encrypted_password: "$2a$10$2DxWWV34BRFJoLboYyWCIeXEtCPYOSe8JqpTmFU6W2i1...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil>
1.9.3-p429 :002 > U.student_classes('math-101').all
ClassInstruction Load (0.2ms) SELECT "class_instructions".* FROM "class_instructions" INNER JOIN "user_roles" ON "user_roles"."id" = "class_instructions"."user_role_id" INNER JOIN roles ON roles.id = user_roles.role_id WHERE (user_role.user_id = 3) AND (roles.name = 'Student') AND (class_instruction.name = 'math-101')
SQLite3::SQLException: no such column: user_role.user_id: SELECT "class_instructions".* FROM "class_instructions" INNER JOIN "user_roles" ON "user_roles"."id" = "class_instructions"."user_role_id" INNER JOIN roles ON roles.id = user_roles.role_id WHERE (user_role.user_id = 3) AND (roles.name = 'Student') AND (class_instruction.name = 'math-101')
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: user_role.user_id: SELECT "class_instructions".* FROM "class_instructions" INNER JOIN "user_roles" ON "user_roles"."id" = "class_instructions"."user_role_id" INNER JOIN roles ON roles.id = user_roles.role_id WHERE (user_role.user_id = 3) AND (roles.name = 'Student') AND (class_instruction.name = 'math-101')
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/sqlite3-1.3.7/lib/sqlite3/database.rb:91:in `initialize'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/sqlite3-1.3.7/lib/sqlite3/database.rb:91:in `new'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/sqlite3-1.3.7/lib/sqlite3/database.rb:91:in `prepare'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/sqlite_adapter.rb:246:in `block in exec_query'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract_adapter.rb:280:in `block in log'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activesupport-3.2.2/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract_adapter.rb:275:in `log'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/sqlite_adapter.rb:242:in `exec_query'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/sqlite_adapter.rb:460:in `select'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract/database_statements.rb:18:in `select_all'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract/query_cache.rb:63:in `select_all'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/querying.rb:38:in `block in find_by_sql'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/explain.rb:40:in `logging_query_plan'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/querying.rb:37:in `find_by_sql'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/relation.rb:171:in `exec_queries'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/relation.rb:160:in `block in to_a'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/explain.rb:33:in `logging_query_plan'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/relation.rb:159:in `to_a'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/relation/finder_methods.rb:159:in `all'
from (irb):2
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/railties-3.2.2/lib/rails/commands/console.rb:47:in `start'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/railties-3.2.2/lib/rails/commands/console.rb:8:in `start'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/railties-3.2.2/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'1.9.3-p429 :003 >

erm,
in this piece of error code.
SQLite3::SQLException: no such column: user_role.user_id: SELECT "class_instructions".* FROM "class_instructions" INNER JOIN "user_roles" ON "user_roles"."id" = "class_instructions"."user_role_id" INNER JOIN roles ON roles.id = user_roles.role_id WHERE (user_role.user_id = 3) AND (roles.name = 'Student') AND (class_instruction.name = 'math-101')
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: user_role.user_id: SELECT "class_instructions".* FROM "class_instructions" INNER JOIN "user_roles" ON "user_roles"."id" = "class_instructions"."user_role_id" INNER JOIN roles ON roles.id = user_roles.role_id WHERE (user_role.user_id = 3) AND (roles.name = 'Student') AND (class_instruction.name = 'math-101')
do you have "class_instructions"."user_role_id" and "class_instructions"."user_role_id" ?
i think in your schema don't have it, am i right ?

Not sure if this is all there is to it, but in this line:
.where(["user_role.user_id = ?", id]) \
You use user_role singular, when the table name is user_roles plural.

Related

how to get records using join between tables

i have doctors table and a users table such that user belongs_to doctor and doctor has_one user as profile. (polymorphic relation)
i want data from doctors table as well as users table where doctor.id = users.profile_id
#search_query = params[:doctor][:query]
#users = User.select("profile_id, username").where("username like ? OR address like ?", #search_query, #search_query )
#doctor = Doctor.select("doctors.start_time, doctors.end_time, doctors.detail, doctors.experience, doctors.license_number, doctors.fee, doctors.available_days, doctors.specialization, doctors.mission_statement, doctors.id, users.id AS user_id, users.name, users.email, users.username, users.address, users.age, users.gender").joins(:user).where("? = doctors.id", #users.each do |u| u.profile_id end)#.joins(:user).where(:users => {:users.profile_id => #doctor.id})
Doctors' migration
create_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
t.string :username, :null => false
t.string :address
t.integer :age
t.string :gender
t.string :name
t.integer :profile_id
t.string :profile_type
Users' migration
class CreateDoctors < ActiveRecord::Migration
def change
create_table :doctors do |t|
t.time :start_time
t.time :end_time
t.text :detail
t.integer :experience
t.text :mission_statement
t.string :license_number
t.integer :fee
t.string :available_days
t.string :specialization
t.timestamps
end
end
end
Doctor.joins("LEFT OUTER JOIN users ON doctors.id = users.profile_id")

rails no such column error

I have the following app. A Movie has many reviews, a moviegoer has many reviews.
When I try to associate a review with a movie I get the following error
Review Load (0.1ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."movie_id" = 5
SQLite3::SQLException: no such column: reviews.movie_id: SELECT "reviews".* FROM "reviews" WHERE "reviews"."movie_id" = 5
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: reviews.movie_id: SELECT "reviews".* FROM "reviews" WHERE "reviews"."movie_id" = 5
after using a sql gui editor I found that the correct query should be
SELECT "reviews".* FROM "reviews" WHERE "movie_id" = 5
review.rb
class Review < ActiveRecord::Base
belongs_to :movie
belongs_to :moviegoer
attr_protected :moviegoer_id
end
movie.rb and moviegoer.rb have
has_many :reviews
in them.
schema.rb
ActiveRecord::Schema.define(:version => 20130222225620) do
create_table "moviegoers", :force => true do |t|
t.string "name"
t.string "provider"
t.string "uid"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "movies", :force => true do |t|
t.string "title"
t.string "rating"
t.text "description"
t.datetime "release_date"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "reviews", :force => true do |t|
t.integer "potatoes"
t.text "comments"
t.integer "moviegoers_id"
t.integer "movies_id"
end
end
What am I doing wrong? why is rails querying "reviews"."movie_id" instead of just "movie_id"?
You have the wrong column name in your migration. The rails convention is that foreign keys are to be singular. If they are not then you need to tell rails what the foreign key is with an options hash on the association.
Either rollback your migration, fix the column name (moviegoers_id is wrong as well) then migrate again, or tell rails the foreign key.
Class Review < ActiveRecord::Base
belongs_to :movie, :foreign_key => 'movies_id'
belongs_to :moviegoer, :foreign_key => 'moviegoers_id'
end
And the same has to happen on the has many side of both models.

has_many :through NameError: uninitialized constant

I just want to make a little join table, eventually storing extra info on that join (which is why I'm not using HABTM). From the rails documentation of associations I've created the following models:
class Physician < ActiveRecord::Base
has_many :appointments
has_many :patients, :through => :appointments
end
class Patient < ActiveRecord::Base
has_many :appointments
has_many :physicians, :through => :appointments
end
class Appointment < ActiveRecord::Base
belongs_to :physicians
belongs_to :patients
end
my schema looks like this:
ActiveRecord::Schema.define(:version => 20130115211859) do
create_table "appointments", :force => true do |t|
t.datetime "date"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "patient_id"
t.integer "physician_id"
end
create_table "patients", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "physicians", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end
When I'm in the console and I create a physician and patient instance:
#patient = Patient.create!
#physician = Physician.create!
And try to associate one to the other
#physician.patients << #patient
I get
NameError: uninitialized constant Physician::Patients
Questions about this example have been asked before but none have address my scenario. Any ideas?
Thanks,
Neil, rails newbie.
The belongs_to calls in your Appointment model should take a singular form, not a plural form:
class Appointment < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
end

Why is the user_id not automatically added upon creation of a comment?

I have a field that creates a comment (named pcomment). I am trying to get it to automatically add the user_id to the pcomment in the pcomment table like it adds the purchase_id automatically. I am not sure why the purchase_id is being recorded in the database but the user_id remains blank for each pcomment. Here is the form for the pcomment.
<%= form_for([purchase, purchase.pcomments.build], :html => { :id => "blah_form" }) do |f| %>
<div class="field">
<h4>What deal are you offering?</h4>
<%= f.text_field :body %>
</div>
<% end %>
It may be that I have to add some hidden_field, but I don't think so. I am using http://ruby.railstutorial.org/book/ruby-on-rails-tutorial#cha-user_microposts as resource and in that the microposts dont have any hidden_field. Instead, the user_id is indexed and it automatically is created upon the creation of a micropost (based on who is signed in at the time). This part is working for me too, adding to my rational that indexing user_id on the pcomments table is enough to automatically generate it. Here is my schema.rb file so that you can see the current state of my database.
ActiveRecord::Schema.define(:version => 20121011085147) do
create_table "pcomments", :force => true do |t|
t.string "body"
t.integer "purchase_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "pcomments", ["purchase_id"], :name => "index_pcomments_on_purchase_id"
add_index "pcomments", ["user_id"], :name => "index_pcomments_on_user_id"
create_table "purchases", :force => true do |t|
t.string "content"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "purchases", ["user_id", "created_at"], :name => "index_purchases_on_user_id_and_created_at"
create_table "sales", :force => true do |t|
t.string "content"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "sales", ["user_id", "created_at"], :name => "index_sales_on_user_id_and_created_at"
create_table "scomments", :force => true do |t|
t.string "body"
t.integer "sale_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "scomments", ["sale_id"], :name => "index_scomments_on_sale_id"
add_index "scomments", ["user_id"], :name => "index_scomments_on_user_id"
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "password_digest"
t.string "remember_token"
t.boolean "admin", :default => false
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["remember_token"], :name => "index_users_on_remember_token"
end
and the reason I know its not working is that I check in the database and the pcomment is successfully created with all columns filled in including purchase_id but the user_id is still blank. also, the user has_many pcomments and has_many purchases. The purchase has_many pcomments and belongs_to user. The pcomment belongs_to user and belong_to purchase.
also, here is the pcomments_controller.rb
class PcommentsController < ApplicationController
before_filter :signed_in_user
def create
#purchase = Purchase.find(params[:purchase_id])
#pcomment = #purchase.pcomments.build(params[:pcomment], :user_id => #purchase.user_id)
#pcomment.purchase = #purchase
if #pcomment.save
flash[:success] = "Offer submited!"
redirect_to :back
else
render 'shared/_pcomment_form'
end
end
def new
#pcomment=purchase.pcomments.new
end
end
def new
#pcomment=purchase.pcomments.new(:user_id => purchase.user_id)
end
end
purchase.pcomments.build builds empty Pcomment object just with purchase_id filled from purchase. To assign also user_id pass the hash with attribute:
purchase.pcomments.build(:user_id => purchase.user_id)

Getting the type a polymorphically associated element in a controller (Rails)?

I have three models: Post (has_many votes as votable), Comment (has_many votes as votable) and Votes (belongs_to votable).
This is votes_controller.rb:
class VotesController < ApplicationController
def vote_up
#votable = WHAT_TO_PLACE_HERE?.find(params[:id])
if #votable.votes.exists?(:user_id => current_user.id)
#notice = 'You already voted'
else
#vote = #post.votes.create(:user_id => current_user.id, :polarity => 1)
#votable.reload
end
respond_to do |format|
format.js
end
end
Relevant schema:
create_table "comments", :force => true do |t|
t.text "content"
t.integer "post_id"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "total_votes", :default => 0
end
add_index "comments", ["post_id", "user_id"], :name => "index_comments_on_micropost_id_and_user_id"
create_table "posts", :force => true do |t|
t.string "content"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "title"
t.integer "comments_count", :default => 0, :null => false
t.integer "total_votes", :default => 0
end
create_table "votes", :force => true do |t|
t.integer "votable_id"
t.string "votable_type"
t.integer "user_id"
t.integer "polarity"
t.integer "total"
t.datetime "created_at"
t.datetime "updated_at"
end
I need way to find the type of the votable element (Post or Comment) so I can assign it to #votable. Any suggestions to accomplish this?
EDIT:
views/posts/show.html.erb:
<%= link_to "Vote Up", vote_up_path(#post), :remote => true, :class => "vote-up" %><br />
routes.rb:
get 'votes/:id/vote_up' => 'votes#vote_up', as: 'vote_up'
Assuming the type is passed via params, you can do this:
params[:votable_type].constantize.find(params[:id])
Please check the documentation for constantize.
You can send the type by appending it as an argument to vote_up_path:
<%= link_to "Vote Up", vote_up_path(#post, :votable_type => 'Post'), :remote => true, :class => "vote-up" %>
Like this it will be added as a get parameter, which shouldn't be a problem. If you don't like this, you have to change your route and add :votable_type somewhere.