I'm working on a multi-site CMS that has a notion of cross-publication among sites. Several types of content (Articles, Events, Bios, etc) can be associated with many Sites and Sites can have many pieces of content. The many-to-many association between content pieces and sites must also support a couple common attributes for each content item associated -- the notion of site origination (is this the original site upon which the content appeared?) as well as a notion of "primary" and "secondary" content status for a given piece of content on a given associated site.
My idea has been to create a polymorphic join model called ContentAssociation, but I'm having trouble getting the polymorphic associations to behave as I expect them to, and I'm wondering if perhaps I'm going about this all wrong.
Here's my setup for the join table and the models:
create_table "content_associations", :force => true do |t|
t.string "associable_type"
t.integer "associable_id"
t.integer "site_id"
t.boolean "primary_eligible"
t.boolean "secondary_eligible"
t.boolean "originating_site"
t.datetime "created_at"
t.datetime "updated_at"
end
class ContentAssociation < ActiveRecord::Base
belongs_to :site
belongs_to :associable, :polymorphic => true
belongs_to :primary_site, :class_name => "Site", :foreign_key => "site_id"
belongs_to :secondary_site, :class_name => "Site", :foreign_key => "site_id"
belongs_to :originating_site, :class_name => "Site", :foreign_key => "site_id"
end
class Site < ActiveRecord::Base
has_many :content_associations, :dependent => :destroy
has_many :articles, :through => :content_associations, :source => :associable, :source_type => "Article"
has_many :events, :through => :content_associations, :source => :associable, :source_type => "Event"
has_many :primary_articles, :through => :content_associations,
:source => :associable,
:source_type => "Article",
:conditions => ["content_associations.primary_eligible = ?" true]
has_many :originating_articles, :through => :content_associations,
:source => :associable,
:source_type => "Article",
:conditions => ["content_associations.originating_site = ?" true]
has_many :secondary_articles, :through => :content_associations,
:source => :associable,
:source_type => "Article",
:conditions => ["content_associations.secondary_eligible = ?" true]
end
class Article < ActiveRecord::Base
has_many :content_associations, :as => :associable, :dependent => :destroy
has_one :originating_site, :through => :content_associations,
:source => :associable,
:conditions => ["content_associations.originating_site = ?" true]
has_many :primary_sites, :through => :content_associations,
:source => :associable
:conditions => ["content_associations.primary_eligible = ?" true]
has_many :secondary_sites, :through => :content_associations,
:source => :associable
:conditions => ["content_associations.secondary_eligible = ?" true]
end
I've tried a lot of variations of the above association declarations, but no matter what I do, I can't seem to get the behavior I want
@site = Site.find(2)
@article = Article.find(23)
@article.originating_site = @site
@site.originating_articles #=>[@article]
or this
@site.primary_articles << @article
@article.primary_sites #=> [@site]
Is Rails' built-in polymorphism the wrong mechanism to use to affect these connections between Sites and their various pieces of content? It seems like it would be useful because of the fact that I need to connect multiple different models to a single common model in a many-to-many way, but I've had a hard time finding any examples using it in this manner.
Perhaps part of the complexity is that I need the association in both directions -- i.e. to see all the Sites that a given Article is associated with and see all of the Articles associated with a given Site. I've heard of the plugin has_many_polymorphs, and it looks like it might solve my problems. But I'm trying to use Rails 3 here and not sure that it's supported yet.
Any help is greatly appreciated -- even if it just sheds more light on my imperfect understanding of the uses of polymorphism in this context.
thanks in advance!