Reputation: 64
Newbie to rails here. I'm making an app to manage users, snippets of text, comments on the snippets, and likes.
Each user has many snippets and has many comments. Each snippet belongs to some user, has many comments, and can have many likes. Each comment belongs to some user, belongs to a snippet, and can have many likes.
My issue is with the Like model. A like will belong to some user, and belong to EITHER a snippet or a comment.
My migration looks like this:
class CreateLikes < ActiveRecord::Migration
def change
create_table :likes do |t|
t.references :user
t.references :snippet # or :comment...?
t.timestamps
end
end
end
My Snippet model:
class Snippet < ActiveRecord::Base
has_many :comments
has_many :likes
belongs_to :user
end
My Comment model:
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :snippet
has_many :likes
end
My Like model:
class Like < ActiveRecord::Base
belongs_to: :user
# belongs to either :snippet or :comment, depending on
# where the like is, and what controller it was submitted to
end
I can't reference both, and I feel like creating a new type of Like for every kind of content in the app would be messy.
How do I decide whether to pick between referencing a snippet or referencing a comment for each like?
Upvotes: 0
Views: 93
Reputation: 2512
You need to take a look at Polymorphic Associations in Rails. RailsCasts hava a good episode on this i.e http://railscasts.com/episodes/154-polymorphic-association.
Here, I would create a polymorphic model for Like and make Comments and Snippets likeable.
class CreateLikes < ActiveRecord::Migration
def change
create_table :likes do |t|
t.integer :likeable_id
t.string :likeable_type
t.references :user
t.timestamps
end
end
end
class Snippet < ActiveRecord::Base
has_many :comments
has_many :likes, as: :likeable
belongs_to :user
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :snippet
has_many :likes, as: :likeable
end
class Like < ActiveRecord::Base
belongs_to: :user
belongs_to :likeable, :polymorphic => true
# belongs to either :snippet or :comment, depending on
# where the like is, and what controller it was submitted to
end
Upvotes: 1
Reputation: 11570
What you're looking for is called a Polymorphic Association and easily accomplished with Rails and active record.
You'll need to modify your Like migration slightly to include an additional _type
column. The easiest way to do this is in the migration.
def change
create_table :likes do |t|
# other columns ...
t.references :likeable, polymorphic: true
t.timestamps
end
end
All this does is create a likeable_id
and a likeable_type
column which will reference a particular id
and class type
(in your case, the type
will be either "Comment" or "Snippet"). After this you can setup your associations like this
class Like < ActiveRecord::Base
belongs_to :likeable, polymorphic: true
end
class Snippet < ActiveRecord::Base
has_many :likes, as: :likeable
end
class Comment < ActiveRecord::Base
has_many :likes, as: :likeable
end
Upvotes: 5