Skip to content

Instantly share code, notes, and snippets.

@krishicks
Created July 9, 2011 12:52
Show Gist options
  • Save krishicks/1073563 to your computer and use it in GitHub Desktop.
Save krishicks/1073563 to your computer and use it in GitHub Desktop.
Double-polymorphic has_many through modeling in Rails
class Article < ActiveRecord::Base
has_many :content_relationships, as: :origin, dependent: :destroy
has_many :related_articles, through: :content_relationships, source: :related_content, source_type: "Article"
has_many :related_videos, through: :content_relationships, source: :related_content, source_type: "Video"
end
class Video < ActiveRecord::Base
has_many :content_relationships, as: :origin, dependent: :destroy
has_many :related_articles, through: :content_relationships, source: :related_content, source_type: "Article"
has_many :related_videos, through: :content_relationships, source: :related_content, source_type: "Video"
end
class ContentRelationship < ActiveRecord::Base
belongs_to :origin, polymorphic: true
belongs_to :related_content, polymorphic: true
end
@chiperific
Copy link

chiperific commented Jun 25, 2021

Does this lead to duplicative, but reversed records on ContentRelationship Or ambiguity on direction?

e.g. Video#5 and Article#41 are related to eachother:

#<ContentRelationship origin_id: 5, origin_type: 'Video', related_content_id: 41, related_content_type: 'Article' >

#<ContentRelationship origin_id: 41, origin_type: 'Article', related_content_id: 5, related_content_type: 'Video' >

Both of these records would be necessary to allow you to traverse both directions, right?

Video.find(5).related_content only works if the first ContentRelationship record exists
Article.find(41).related_content only works if the second ContentRelationship record exists

These rely on performing the JOIN only on the origin column, but SQL allows for AND and OR on joins. I just don't think Rails provides a way to define multiple sources in a has_many

@krishicks
Copy link
Author

Sorry to say, I have no idea. What you said sounds plausible, though. Note, this gist is 10 years old!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment