Has many through with different foreign key - ruby-on-rails

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".

Related

No column error in Many to many polymorphic association in rails

Book Model is
class Book < ActiveRecord::Base
has_many :tokens, :through => :taggings
has_many :taggings, :as => :taggable
end
Token Model is
class Token < ActiveRecord::Base
has_many :books, :through => :taggings, :source => :taggable, :source_type => "Book"
has_many :taggings
end
Taggings Model is
class Tagging < ActiveRecord::Base
belongs_to :token
belongs_to :taggable, :polymorphic => true
end
When I get Book.first.tokens OR Token.first.books It gives error
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: taggings.token_id: SELECT "tokens".* FROM "tokens" INNER JOIN "taggings" ON "tokens"."id" = "taggings"."token_id" WHERE "taggings"."taggable_id" = ? AND "taggings"."taggable_type" = ?
Have you created all the necessary columns for your associations?
Your schema for your taggings table should look similar to this
create_table "taggings", force: :cascade do |t|
t.integer "token_id", limit: 4
t.integer "taggable_id", limit: 4
t.string "taggable_type", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
I think you are missing the token_id column or forgot to perform a migration.

Unexpected behaviour in rails when defining class_name in habtm

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.

Rails nested where clause on join table

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

Rails: Friendship join table clarification

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.

how to search one object and return another related object

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

Resources