I have two models (Course and Dancer). A course can have many dancers (students) and teachers (also dancers). Teachers can be students of other courses.
I define the tables as follows:
create_table "course_enrollments", :force => true do |t|
t.integer "dancer_id", :null => false
t.integer "course_id", :null => false
t.datetime "attended_on", :null => false
end
create_table "courses", :force => true do |t|
t.string "name", :null => false
t.string "genre"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "courses_teachers", :id => false, :force => true do |t|
t.integer "course_id", :null => false
t.integer "teacher_id", :null => false
end
create_table "dancers", :force => true do |t|
t.string "first_name", :null => false
t.string "last_name", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
And the classes:
class Dancer < ActiveRecord::Base
has_many :course_enrollments
has_many :courses, :through => :course_enrollments
has_many :teachers, :through => :courses
end
class Course < ActiveRecord::Base
has_many :course_enrollments
has_many :dancers, :through => :course_enrollments
has_and_belongs_to_many :teachers, :class_name => 'Dancer'
end
class CourseEnrollment < ActiveRecord::Base
belongs_to :dancer
belongs_to :course
end
Based on the guide (http://guides.rubyonrails.org/association_basics.html), I would expect the teachers attribute of Course to look for the table courses_teachers and use teacher_id as the foreign key. Instead it's looking for courses_dancers and dancer_id, presumably from setting class_name to 'Dancer'. Is this by design or is it a bug? I can get it to work if I instead do:
has_and_belongs_to_many :teachers, :class_name => 'Dancer', :join_table => :courses_teachers
And rename teacher_id to dancer_id in the courses_teachers table
Is there a better approach?
If you look at the api for habtm, there's an option for foreign_key and association_foreign_key. Try the following
has_and_belongs_to_many :teachers, :class_name => 'Dancer', :join_table => :courses_teachers, :foreign_key => :course_id, :association_foreign_key => :teacher_id
I'm not sure if it will work without passing foreign_key option but it probably will so try without it first.
Related
I cannot make good associations when the foreign key has not the default name.
I would like to access to all subjects which belongs_to one participant (foreign key = questioner_id).
It raise me an error
p = Participant.first
p.subjects
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: subject_participants.participant_id: SELECT "participants".* FROM "participants" INNER JOIN "subject_participants" ON "participants"."id" = "subject_participants"."subject_id" WHERE "subject_participants"."participant_id" = ?
Why does it looks for subject_participants.participant_id ? It's just a has_many association, I don't think that subject_participants table should be called in this case...
interested_id and questioner_id are from the same model but not the same role. One has to go through subject_participants table and the other has to go directly in subjects table
My models :
participant.rb
class Participant < ActiveRecord::Base
has_many :subjects, foreign_key: "questioner_id", class_name: "Participant" #questioner
has_many :subjects, through: :subject_participants, foreign_key: "interested", class_name: "Participant" #interested
has_many :subject_participants
has_many :conference_participants
has_many :conferences, through: :conference_participants
end
subject.rb
class Subject < ActiveRecord::Base
validates_presence_of :title, :questioner, :conference, :description
has_many :subject_participants
has_many :interested, through: :subject_participants, :class_name => "Participant" #interested
belongs_to :questioner, :class_name => "Participant"
belongs_to :conference
end
subject_participant.rb
class SubjectParticipant < ActiveRecord::Base
validates_presence_of :interested_id, :subject_id
belongs_to :interested, :class_name => "Participant"
belongs_to :subject
end
schema.rb
create_table "participants", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
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"
end
add_index "participants", ["email"], name: "index_participants_on_email", unique: true
add_index "participants", ["reset_password_token"], name: "index_participants_on_reset_password_token", unique: true
create_table "subject_participants", force: :cascade do |t|
t.integer "interested_id"
t.integer "subject_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "subjects", force: :cascade do |t|
t.string "title", null: false
t.text "description"
t.integer "questioner_id", null: false
t.integer "conference_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Change your participant.rb to
class Participant < ActiveRecord::Base
.....
has_many :subject_participants,class_name: "SubjectParticipant", foreign_key: "interested_id"
end
You make me find the solution, thanks for help :
participant.rb
class Participant < ActiveRecord::Base
has_many :subject_participants, class_name: "SubjectParticipant", foreign_key: "interested_id"
has_many :subjects_interested_in, through: :subject_participants, :source => "subject"
has_many :subjects, foreign_key: "questioner_id"
has_many :conference_participants
has_many :conferences, through: :conference_participants
end
subject.rb
class Subject < ActiveRecord::Base
validates_presence_of :title, :questioner, :conference, :description
has_many :subject_participants
has_many :interested, through: :subject_participants #interested
belongs_to :questioner, class_name: "Participant"
belongs_to :conference
end
I have two models with associations through a join table. Here is the schema...
create_table "group_shots", :force => true do |t|
t.integer "shot_id"
t.integer "group_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "groups", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "shots", :force => true do |t|
t.string "name"
t.integer "comedian_id"
t.string "pic_file_name"
t.string "pic_content_type"
In my groups controller I'm trying to do something like...
def show
#group = Group.find(params[:id])
#shots = Shot.where(GroupShot.where(:group_id => #group.id))
I am getting the error "Cannot visit ActiveRecord::Relation". What is the right way to do this? I'm using Rails 3.2
EDIT
...my models are...
#app/models/group_shot.rb
class GroupShot < ActiveRecord::Base
belongs_to :shots
belongs_to :groups
attr_accessible :group_id, :shot_id
#app/models/group.rb
class Group < ActiveRecord::Base
has_many :shots, through: :group_shot
attr_accessible :name
end
#app/models/shot.rb
class Shot < ActiveRecord::Base
has_many :groups, :through => :group_shot
Assuming you have your group model set up like:
class Group < ActiveRecord::Base
has_many :group_shots
has_many :shots, through: :group_shots
end
class Shot < ActiveRecord::Base
has_many :group_shots
has_many :groups, :through => :group_shots
end
class GroupShot < ActiveRecord::Base
belongs_to :shot
belongs_to :group
end
Then you can do something like
#shots = #group.shots
If the "associations through" is configured right:
#group = Group.find(params[:id])
#shots = #group.shots
I'm currently working on my first project and am trying to add "friending" to my app. However, I'm having a little trouble grasping the concept of the friendships model, since attributes that don't seem to exist in my database seem to just work.
I have my model and database columns listed below. I understand that this is a join table, but in the user model where do friends, requested_friends, and pending friends come from if they don't exist in the friendships table? Is it because it is a virtual join table so that I could just add whatever columns I need without having to migrate them?
Also, the tutorial eventually does #user.pending_friends.each even though that column doesn't exist in my users table. I'm pretty confused on this part.
Currently I'm going through this brief tutorial: http://railsforum.com/viewtopic.php?id=16760
Here are my files:
user model
class User < ActiveRecord::Base
...
...
has_many :friendships, :dependent => :destroy
has_many :friends, :through => :friendships, :conditions => "status = 'accepted'"
has_many :requested_friends, :through => :friendships, :source => :friend, :conditions => "status = 'requested'", :order => :created_at
has_many :pending_friends, :through => :friendships, :source => :friend, :conditions => "status = 'pending", :order => :created_at
end
friendship model
class Friendship < ActiveRecord::Base
attr_accessible :friend_id
belongs_to :user
belongs_to :friend, :class_name => "User"
end
schema
create_table "friendships", :force => true do |t|
t.integer "user_id"
t.integer "friend_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
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"
end
You probably forgotten to migrate since you don't have status column in your schema. Associations you're referring is bound to friend_id key that exist in friendships table. Last 2 associations is just using foreign key defined for belongs_to :friend. Please have a look here. I guess such associations can work without actual attribute if this is what you meant, you just don't get condition: functionality here and all 3 last associations will return same values.
I have the following :has_many :through relation.
Associations
class Profile < ActiveRecord::Base
has_many :teams
has_many :projects, :class_name => "Project", :through => :teams
has_many :leads, :class_name => "Projects"
class Project < ActiveRecord::Base
has_many :teams
has_many :developers, :class_name => "Profile", :through => :teams
belongs_to :lead, :class_name => "Profile", :foreign_key => "developer_lead"
class Team < ActiveRecord::Base
belongs_to :developer, :class_name => "Profile"
belongs_to :project
When I try to get a Profiles projects the relationship doesn't use the right key in the teams table.
Rails C
1.9.3p194 :001 > Profile.first.projects
Profile Load (0.2ms) SELECT "profiles".* FROM "profiles" LIMIT 1
Project Load (0.2ms) SELECT "projects".* FROM "projects" INNER JOIN "teams" ON "projects"."id" =
"teams"."project_id" WHERE "teams"."profile_id" = 1
It should be using "teams"."developer_id" = 1
I've tried using a :foreign_key => "developer_id" in both the Profile and Project models, but nothing seems to work.
I feel like the changes to the models I've been making aren't taking any effects, after each change I've been restarting the rails console though.
Schema
create_table "profiles", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "projects", :force => true do |t|
t.integer "developer_lead"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "teams", :id => false, :force => true do |t|
t.integer "developer_id"
t.integer "project_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
:foreign_key => "developer_id" belongs with has_many :teams.
Also, it makes your code clearer if you stick to rails conventions and end all foreign_key names with "_id", as in "developer_lead_id".
I am trying to create search form when user search for a course it returns list of user's names who are taking that course.So i have user table,course table and user-course join table.I want o use metasearch or ransack.But i wonder how i would use these in my case.Thank you in advance.
create_table "users", :force => true do |t|
t.string "firstname"
t.string "email"
t.string "encrypted_password", :limit => 128, :default => "", :null => false
t.string "password_salt", :default => "", :null => false
end
create_table "courses", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "school_id", :null => false
end
create_table "user_courses", :force => true do |t|
t.integer "user_id", :null => false
t.integer "course_id", :null => false
t.boolean "active", :null => false
end
class User < ActiveRecord::Base
has_many :user_courses
has_many :courses, :through => :user_courses
has_many :active_courses, :through => :user_courses, :source => :course, :conditions => {'user_courses.active' => true}
has_many :taken_courses, :through => :user_courses, :source => :course, :conditions => {'user_courses.active' => false}
end
class UserCourse < ActiveRecord::Base
belongs_to :user
belongs_to :course
end
class Course < ActiveRecord::Base
validates_presence_of :name
has_many :user_courses
belongs_to :school
end
You can add this to your Course model:
has_many :users, :through => :user_courses
Then you can get the users from a course like so
Course.find(1).users