Поддержка полиморфизма значительно улучшилась с первых дней. Вы сможете достичь этого в 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