您可以尝试混合模型方法,但设置工作量很大。以性能换取更高效的数据库存储,这有点杂乱无章。
这个想法是您使用 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 现在将列出所有类型的帖子。唯一的缺点是获取帖子时不会显示详细信息字段。