Reputation: 782
I need to link Comments to a Post. However the Comment could be (user generated) a simple text, (system generated) a link or an (system generated) image.
At first they all shared the same attributes. So I just needed to create a category attribute, and do different stuff with the text attribute based on that category.
example:
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :author, :class_name => "User"
CATEGORY_POST = "post"
CATEGORY_IMAGE = "image"
CATEGORY_LINK = "link"
validates :text, :author, :category, :post, :presence => true
validates_inclusion_of :category, :in => [CATEGORY_POST, CATEGORY_IMAGE, CATEGORY_LINK]
attr_accessible :author, :text, :category, :post
def is_post?
self.category == CATEGORY_POST
end
def is_link?
self.category == CATEGORY_LINK
end
def is_image?
self.category == CATEGORY_IMAGE
end
end
However this wil not suffice now, because I doesn't feel clean to dump every value in a generic "text" property. So I was thinking about create a polymorphic model (and if needed in a factory pattern). But when I googled about polymorphic models, I get examples like a Comment on a Post, but the same Comment on a Page, kind of relations. Is my understanding of polymorphic different (a model that acts different in different situations, compared to a model that acts the same under different scopes)?
So how would I set up this kind of relationship?
I was thinking of (and please correct me)
Post
id
Comment
id
post_id
category (a enum/string or integer)
type_id (references either PostComment, LinkComment or ImageComment based on category)
author_id
PostComment
id
text
LinkComment
id
link
ImageComment
id
path
User (aka Author)
id
name
But I have no clue how to setup the model so that I can call post.comments (or author.comments) to get all comments. A nice to have would be that the creation of a comment would be through comment and not link/image/postcomment (comment acting as the factory)
My main question is, how to setup up the activerecord models, so the relations stay intact (a author has comments and a post has comments. Comments being either a Link, Image or Postcomment)
Upvotes: 0
Views: 148
Reputation: 29599
I'm going to answer only your main question, the model setup. Given the columns and tables you used in your question, with the exception of Comment, you can use the following setup.
# comment.rb
# change category to category_type
# change type_id to category_id
class Comment < ActiveRecord::Base
belongs_to :category, polymorphic: true
belongs_to :post
belongs_to :author, class_name: 'User'
end
class PostComment < ActiveRecord::Base
has_one :comment, as: :category
end
class LinkComment < ActiveRecord::Base
has_one :comment, as: :category
end
class ImageComment < ActiveRecord::Base
has_one :comment, as: :category
end
with that setup, you can do the following.
>> post = Post.first
>> comments = post.comments
>> comments.each do |comment|
case comment.category_type
when 'ImageComment'
puts comment.category.path
when 'LinkComment'
puts comment.category.link
when 'PostComment'
puts comment.category.text
end
end
Upvotes: 1