从早期开始,对多态性的支持有了显着改善。您应该能够在 Rails 2.3 中通过为所有模型使用单个连接表来实现这一点——一个关系模型。
class Relation
belongs_to :owner, :polymorphic => true
belongs_to :child_item, :polymorphic => true
end
class Book
has_many :pwned_relations, :as => :owner, :class_name => 'Relation'
has_many :pwning_relations, :as => :child_item, :class_name => 'Relation'
# and so on for each type of relation
has_many :pwned_movies, :through => :pwned_relations,
:source => :child_item, :source_type => 'Movie'
has_many :pwning_movies, :through => :pwning_relations,
:source => :owner, :source_type => 'Movie'
end
这种数据结构的一个缺点是,您必须为可能相等的配对创建两个不同的角色。如果我想查看我的书的所有相关电影,我必须将这些集合添加在一起:
( pwned_movies + pwning_movies ).uniq
这个问题的一个常见例子是社交网络应用程序中的“朋友”关系。
Insoshi 使用的一种解决方案是在连接模型上注册一个after_create 回调(在本例中为Relation),这会创建反向关系。 after_destroy 回调同样是必要的,但通过这种方式,以一些额外的数据库存储为代价,您可以确信您将在单个数据库查询中获得所有相关电影。
class Relation
after_create do
unless Relation.first :conditions =>
[ 'owner_id = ? and owner_type = ? and child_item_id = ? and child_item_type = ?', child_item_id, child_item_type, owner_id, owner_type ]
Relation.create :owner => child_item, :child_item => owner
end
end
end