Reputation: 22044
I'm new to rails, I was thinking about this idea this afternoon
here's my code:
video table migration file:
class CreateVideos < ActiveRecord::Migration
def self.up
create_table :videos do |t|
t.string :title
t.string :drummer_id
t.timestamps
end
end
def self.down
drop_table :videos
end
end
drummer table migration file:
class CreateDrummers < ActiveRecord::Migration
def self.up
create_table :drummers do |t|
t.string :first_name
t.string :video_id
t.timestamps
end
end
def self.down drop_table :drummers end end
drummer.rb
class Drummer < ActiveRecord::Base
belongs_to :video
has_many :videos
end
video.rb
class Video < ActiveRecord::Base has_many :drummers belongs_to :drummer end
as far as I know
Drummer.create(:first_name => "Jojo")
Drummer.find_by_first_name("Jojo").videos.create(:title => "JojoVideo1")
it's ok
but in the other side, there's nothing!
Video.find_by_title("JojoVideo1").drummers
=>[]
I check the foreign keys all match, But I don't know what the query above return a blank array.
Upvotes: 0
Views: 88
Reputation: 4203
> Drummer.all
=> [#<Drummer id: 1, first_name: "Jojo", video_id: nil, created_at: "2010-12-10 11:04:48", updated_at: "2010-12-10 11:04:48">]
> Video.all
=> [#<Video id: 1, title: "JojoVideo1", drummer_id: "1", created_at: "2010-12-10 11:04:48", updated_at: "2010-12-10 11:04:48">]
> Video.all.first.drummer
=> #<Drummer id: 1, first_name: "Jojo", video_id: nil, created_at: "2010-12-10 11:04:48", updated_at: "2010-12-10 11:04:48">
> Video.all.first.drummers
=> []
And from test/development.log:
Video Load (0.3ms) SELECT "videos".* FROM "videos"
Drummer Load (0.3ms) SELECT "drummers".* FROM "drummers" WHERE ("drummers"."id" = 1) LIMIT 1
Video Load (0.3ms) SELECT "videos".* FROM "videos"
Drummer Load (0.3ms) SELECT "drummers".* FROM "drummers" WHERE ("drummers".video_id = 1)
Video.all.first.drummer works, because it is found by going to the video then checking their drummer id. The other doesn't work because it tries to find drummers with a video_id, and the way we created the video didn't set the drummer's video_id.
We can construct a video/drummer pair with the opposite problem:
d = Drummer.first
d.create_video(:title => "JojoVideo2")
d.save
That new video behaves well for drummers, but poorly for drummer - because this time, the drummer has a video_id but the video has no drummer_id.
The practical upshot of which is that you should do what Rohit said :)
Upvotes: 1
Reputation: 5721
I don't know what is wrong in your code. But i would like to suggest another way around. You can create a join model which will handle the many to many association for you. Using the join model you can get better control over your code. This can be done as below:
class A < ActiveRecord::Base
has_many :cs
has_many :bs, :through => cs
end
class B < ActiveRecord::Base
has_many :cs
has_many :as, :through => cs
end
class C < ActiveRecord::Base
belongs_to :as
belongs_to :bs
end
and the migration for each model as below
class CreateAs < ActiveRecord::Migration
def self.up
create_table :as do |t|
t.string :title
t.timestamps
end
end
def self.down
drop_table :as
end
end
class CreateBs < ActiveRecord::Migration
def self.up
create_table :bs do |t|
t.string :title
t.timestamps
end
end
def self.down
drop_table :bs
end
end
class CreateCs < ActiveRecord::Migration
def self.up
create_table :cs do |t|
t.references :as
t.references :bs
t.timestamps
end
end
def self.down
drop_table :cs
end
end
another way around is by just creating a join table without a model. This can be done by:-
class A < ActiveRecord::Base has_and_belongs_to_many :bs end
class B < ActiveRecord::Base has_and_belongs_to_many :as end
Hope you have a better idea.
Upvotes: 1