Reputation: 131
I am pretty new to rails. I am trying to figure out the most efficient way to create a relationship between two models that states:
This is what I am thinking of doing. Does it make sense ?
class User < ActiveRecord::Base
has_many :songs #songs this user has favorited
end
class Song < ActiveRecord::Base
belongs_to :user #the user whom submitted this song
end
My concern about this method is that I'm unsure about the efficiency of doing query on every song in the database just to figure out which songs a particular user owns. Is there a different way I should be thinking about this ?
By the way, is there a method by which I can call the attribute something different than it's model name. So rather than User.find(1).songs[0]
I could say User.find(1).favorites[0]
even though the model is still a "Song".
Upvotes: 2
Views: 3490
Reputation: 35531
You'll need 2 separate relationships between the User and Song models. Namely, you'll need an 'owner' relationship and a 'favorite' relationship. The 'owner' relationship can be a simple has_many/belongs_to as you have it now. The 'favorite' relationship is many-to-many and will need a join table used either as a habtm
table or a first class model with a has_many through
relationship as explained here.
The generallly recommended approach is to use has_many through
as it gives you better control:
class User
has_many :songs # these are songs 'owned' by the user
has_many :user_favorite_songs
has_many :favorite_songs, :through => :user_favorite_songs # these are the favorites
end
class Song
belongs_to :user
has_many :user_favorite_songs
end
class UserFavoriteSong
belongs_to :user
belongs_to :favorite_song, :class_name => 'Song', :foreign_key => :song_id
end
Upvotes: 7
Reputation: 2188
I haven't tested this code, but you'll need something like this.
class User < ActiveRecord::Base
has_and_belongs_to_many :favorites, :class_name => "Song" #user's favorited songs
end
class Song < ActiveRecord::Base
belongs_to :user #the user who submitted the song
has_and_belongs_to_many :user, :as => :favorite
end
And since multiple users can favorite a song, you'll need a 'join table'
CreateUsersFavorites < ActiveRecord::Migration
def up
create_table :users_favorites do |t|
t.references :user
t.references :favorite
end
create_index :users_favorites, :user_id
create_index :users_favorites, :favorite_id
end
def down
drop_table :users_favorites
end
end
Also, I highly recommend taking a look at the rails guide for active record relationships.
Upvotes: 1
Reputation: 2565
This looks perfectly fine.
Rails associations try to be most efficient - don't prematurely optimize.
You can alias the association's name like so:
class User < ActiveRecord::Base
has_many :favorites, class_name: 'Song'
end
see the docs about associations.
Regarding performance anyway, you might want to have a look at the :inverse_of
association option.
Upvotes: 2