2013-02-19 50 views
0

我需要将评论链接到帖子。然而,Comment可以是(用户生成的)简单的文本,(系统生成的)链接或(系统生成的)图像。如何创建多态模型

起初他们都共享相同的属性。所以我只需要创建一个category属性,并根据该类别使用text属性完成不同的事情。

例如:

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 

然而,这西港岛线不是现在足够了,因为我不觉得干净倾倒在一个通用的“文本”属性的每个值。所以我正在考虑创建一个多态模型(如果需要在工厂模式中)。但是当我搜索多态模型时,我得到了一些例子,比如对帖子的评论,但是同一个页面上的评论,这种关系。我对多态性不同的理解(与在不同范围内行为相同的模型相比,在不同情况下行为不同的模型)?

那么我将如何建立这种关系?

我在想(和请指正)

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 

但我不知道如何建立一个模型以便我可以调用post.comments(或author.comments)来获取所有的意见。一个不错的将是一个评论的创建将通过评论,而不是链接/图像/ postcomment(注释充当工厂)

主要问题是,如何设置了ActiveRecord的车型,所以关系保持不变(作者有评论和帖子有评论,评论可以是链接,图片或Postcomment)

回答

1

我只会回答你的主要问题,模型设置。鉴于您在问题中使用的列和表,除了注释之外,您可以使用以下设置。

# 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 

使用该设置,您可以执行以下操作。

>> 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