我应该使用哪种关联来描述Ruby on Rails中的“事物类型”?

时间:2010-02-05 21:37:49

标签: ruby-on-rails associations

我希望能够使用RoR关联描述不同类型的模型。一个例子:

型号:

ImagePost
POST_ID:整数
网址:字符串

MessagePost
POST_ID:整数
消息:字符串

ImagePost和MessagePost是一种Post。我想@posts = Post.all检索两种类型的帖子,并允许我通过@ posts.url或@ posts.message访问他们的属性。

我确定我遗漏了一些简单的东西,请赐教!

干杯,

本。

2 个答案:

答案 0 :(得分:3)

查看单表继承的概念 - 基本思想是您将拥有一个具有Type列的Post表,因此给定的ImagePost仍然只是Post表中的一行。 Post表将包含所有可能属性的列,因此它将包含url和message列。

然后相应的模型类将继承自Post:ImagePost

答案 1 :(得分:0)

您可以尝试使用混合模型方法,但设置工作量相当大。它可以用来交换性能以获得更高效的数据库存储。

这个想法是你使用STI来处理所有常见的Post字段,并将每个子类的唯一字段委托给另一个表并且急切地加载该关联。

基础Post类看起来像这样。请注意,class_eval可以被抽象为一个模块,该模块被包含并扩展到子类中。

#columns: id:integer, timestamps, user_id:integer, 
#  topic_id:integer, type:string
class Post < ActiveRecord::Base
  # common methods/validations/associations
  belongs_to :user
  belongs_to :topic 

  def self.relate_to_detail
    class_eval <<-"EOF"
      has_one :detail, :class_name => "#{self.name}Detail"
      accepts_nested_attributes_for :detail

      default_scope :include => :detail

      def method_missing(method, *args)
        build_detail if detail.nil?
        if detail && detail.respond_to?(method, true)
          detail.send(method, *args)
        else 
          super(method, *args)
        end
      end

      def respond_to?( method, include_private = false)
        build_detail if detail.nil?
        super(method, include_private) || 
          detail.respond_to?(method, include_private)
      end
    EOF
  end
end

然后,您需要为每种类型定义子类和详细信息类。

#uses posts table
class ImagePost < Post
  relate_to_detail
end

#columns: id, image_post_id, url:string, height:integer, :width:integer
class ImagePostDetail < ActiveRecord::Base
  belongs_to :image_post
end

#uses posts table
class MessagePost < Post
  relate_to_detail
end

#columns: id, message_post_id, message:string
class MessagePostDetail < ActiveRecord::Base
  belongs_to :image_post
end

现在我们可以这样做:

@user.message_posts.create(:message => "This is a message")
@image_post.url

这将创建一个新的MessagePost,其中user_id,timestamps,post_id,post_type都存储在posts表中,而消息存储在MessagePostDetails表中并分别返回ImagePost的url。

新的method_missing和respond_to?定义有助于隐藏分裂。

@Post.all现在将列出所有类型的帖子。唯一的缺点是,当您获取帖子时,不会显示详细信息字段。