Hi Wenhan,
This is how I set up my association and I think it works well… I’m
using has_many through instead of has_and_belongs_to_many. I think that
using has_many through is now more widely accepted than it’s
predecessor.
Anyways, on to the show. Here’s what we have:
Models
User:
has_many :videos, :foreign_key=>‘added_by’ # in retrospect that might
not be the best name. You could try contributor_id, maybe.
has_many :video_collections
has_many :collected_videos, :through=>:video_collections,
:source=>:video # We have to specify a source since we aren’t really
following the naming convention.
Video:
belongs_to :user, :foreign_key=>‘added_by’
has_many :video_collections
has_many :collectors, :through=>:video_collections,:source=>:user
VideoCollection:
belongs_to :user
belongs_to :video
Next up, Simple Migrations for the Models!
Users
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :name
t.timestamps
end
User.create!(:name=>"Lake")
end
def self.down
drop_table :users
end
end
Videos
class CreateVideos < ActiveRecord::Migration
def self.up
create_table :videos do |t|
t.string :title
t.integer :added_by
t.timestamps
end
Video.create!(:title=>"Gone With The Wind", :added_by=>1)
end
def self.down
drop_table :videos
end
end
Video Collections (rumor has it that you can pass :id=>false here, but I
forgot to do that when I generated this)
class CreateVideoCollections < ActiveRecord::Migration
def self.up
create_table :video_collections do |t|
t.integer :user_id
t.integer :video_id
t.timestamps
end
VideoCollection.create!(:user_id=>1, :video_id=>1)
end
def self.down
drop_table :video_collections
end
end
Okay, so we have our migrations setup and the next thing we cna do is
Migrate:
rake db:create:all;rake db:migrate
Then fire up the script/console in your rails_root directory: ruby
script/console
Let’s see what happens (ps. We already created some rows in the
migrations):
#Make sure all our entities are there:
User.find(1)
=> #<User id: 1, name: “Lake”, created_at: “2008-08-11 20:53:24”,
updated_at: “2008-08-11 20:53:24”>
Video.find(1)
=> #<Video id: 1, title: “Gone With The Wind”, added_by: 1, created_at:
“2008-08-11 20:53:24”, updated_at: “2008-08-11 20:53:24”>
VideoCollection.find(1)
=> #<VideoCollection id: 1, user_id: 1, video_id: 1, created_at:
“2008-08-11 20:53:24”, updated_at: “2008-08-11 20:53:24”>
Check videos associated with users
User.find(1).videos
=> [#<Video id: 1, title: “Gone With The Wind”, added_by: 1, created_at:
“2008-08-11 20:53:24”, updated_at: “2008-08-11 20:53:24”>]
Check user associated with video
Video.find(1).user
=> #<User id: 1, name: “Lake”, created_at: “2008-08-11 20:53:24”,
updated_at: “2008-08-11 20:53:24”>
Check collected videos associated with user
User.find(1).collected_videos
=> [#<Video id: 1, title: “Gone With The Wind”, added_by: 1, created_at:
“2008-08-11 20:53:24”, updated_at: “2008-08-11 20:53:24”>]
Check collector associated with video
Video.find(1).collectors
=> [#<User id: 1, name: “Lake”, created_at: “2008-08-11 20:53:24”,
updated_at: “2008-08-11 20:53:24”>]
Let’s make sure we really are getting different associations since
it’s only fairly proven.
Let’s create a new video
Video.create!(:title=>‘Gone With The Wind’, :added_by=>2)
=> #<Video id: 2, title: “Gone With The Wind”, added_by: 2, created_at:
“2008-08-11 20:58:43”, updated_at: “2008-08-11 20:58:43”>
Let’s create a new video collection for user 1 and video 2
VideoCollection.create(:user_id=>1, :video_id=>2)
=> #<VideoCollection id: 2, user_id: 1, video_id: 2, created_at:
“2008-08-11 20:59:26”, updated_at: “2008-08-11 20:59:26”>
Now let’s ask the user for it’s collected videos
User.find(1).collected_videos
=> [#<Video id: 1, title: “Gone With The Wind”, added_by: 1, created_at:
“2008-08-11 20:53:24”, updated_at: “2008-08-11 20:53:24”>, #<Video id:
2, title: “Gone With The Wind”, added_by: 2, created_at: “2008-08-11
20:58:43”, updated_at: “2008-08-11 20:58:43”>]
And now for User 1’s videos that he added
User.find(1).videos
=> [#<Video id: 1, title: “Gone With The Wind”, added_by: 1, created_at:
“2008-08-11 20:53:24”, updated_at: “2008-08-11 20:53:24”>]
Hope that helps some.
Lake
Wenhan Zhou wrote:
Hi, This is the scenario
A user can create videos and collect videos.
I was coding the creation side of the videos so I was using a belongs_to
and a has_many.
Then when I came to the part of collecting the videos, I am stumped with
how to implement the association.
Normally I would just use a table with user_id and video_id.
But in this case, this would conflict with my earlier code.
so the question is this: how do I implement an association for the
scenario belong.
A user can create multiple video that are shown on his profile page
(1 to Many)
user.rb :has_many :videos
video.rb :belongs_to :user
user table has a coloum called video_id
A user can also collect a video. This list is shown as videos favorited
by this user(Each video can also be favourite by many people)
(many to many)
user.rb : has_and_belongs_to_many :videos
video.rb :has_and_belongs_to_many :users
created a new table called user_video with user_id & video_id
Since the 2 associations are for exactly the same models,
what happens when I call @user.videos
will I
- Get the list of videos created by this user
- Get the list of videos collected by this user
- the system goes bonkers
Is this the wrong way to implement this?