我希望能够使用RoR关联描述不同类型的模型。一个例子:
型号:
交
ImagePost
POST_ID:整数
网址:字符串
MessagePost
POST_ID:整数
消息:字符串
ImagePost和MessagePost是一种Post。我想@posts = Post.all检索两种类型的帖子,并允许我通过@ posts.url或@ posts.message访问他们的属性。
我确定我遗漏了一些简单的东西,请赐教!
干杯,
本。
答案 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
现在将列出所有类型的帖子。唯一的缺点是,当您获取帖子时,不会显示详细信息字段。