如何创建多态模型

时间:2013-02-19 10:00:54

标签: ruby-on-rails ruby-on-rails-3

我需要将评论链接到帖子。但是,注释可以(用户生成)一个简单的文本,(系统生成的)链接或(系统生成的)图像。

起初他们都共享相同的属性。所以我只需要创建一个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

然而,现在这还不够,因为我觉得将每个值都转储到通用的“text”属性中并不干净。所以我在考虑创建一个多态模型(如果需要在工厂模式中)。但是当我搜索关于多态模型的时候,我得到的例子就像评论帖子一样,但同样的关于页面的评论,关系的类型。我对多态的理解是否不同(在不同情况下,与在不同范围内行为相同的模型相比,模型的行为不同)?

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

我在考虑(请纠正我)

 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)来获取所有评论。很高兴的是,评论的创建将通过评论而不是链接/图像/后评论(作为工厂的评论)

我的主要问题是,如何设置activerecord模型,因此关系保持不变(作者有评论,帖子有评论。评论是链接,图片或后评论)< / p>

1 个答案:

答案 0 :(得分:1)

我只会回答你的主要问题,即模型设置。给定您在问题中使用的列和表,除了Comment,您可以使用以下设置。

 # 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