Вы можете попробовать смешанный модельный подход, но это достаточно много для настройки. Это своего рода клочок, который меняет производительность для более эффективного хранения базы данных.
Идея состоит в том, что вы используете 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
Затем вам нужно будет определить класс sub и detail для каждого типа.
#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 и возвращает URL-адрес ImagePost соответственно.
Новый метод_missing и response_to? определения работают магию, чтобы скрыть разделение.
@Post.all
теперь будет перечислять сообщения всех типов. Единственным недостатком является то, что подробные поля не будут отображаться при получении сообщения.