In ActiveRecord, has_many :through, and Polymorphic Associations, the OP's example requests ignoring the possible superclass of Alien
and Person
(SentientBeing
). This is where my question lies.
class Widget < ActiveRecord::Base
has_many :widget_groupings
has_many :people, :through => :widget_groupings, :source => :person, :source_type => 'Person'
has_many :aliens, :through => :widget_groupings, :source => :alien, :source_type => 'Alien'
end
SentientBeing < ActiveRecord::Base
has_many :widget_groupings, :as => grouper
has_many :widgets, :through => :widget_groupings
end
class Person < SentientBeing
end
class Alien < SentientBeing
end
In this modified example the grouper_type
value for Alien
and Person
are now both stored by Rails as SentientBeing
(Rails seeks out the base class for this grouper_type
value).
What is the proper way to modify the has_many
's in Widget
to filter by type in such a case? I want to be able to do Widget.find(n).people
and Widget.find(n).aliens
, but currently both of these methods (.people
and .aliens
) return empty set []
because grouper_type
is always SentientBeing
.
Polymorphic relationship in Rails refers to a type of Active Record association. This concept is used to attach a model to another model that can be of a different type by only having to define one association.
They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile , then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user . To determine who "has" the other object, look at where the foreign key is.
2.9 Polymorphic Associations A slightly more advanced twist on associations is the polymorphic association. With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a picture model that belongs to either an employee model or a product model.
The basic structure of a polymorphic association (PA)sets up 2 columns in the comment table. (This is different from a typical one-to-many association, where we'd only need one column that references the id's of the model it belongs to). For a PA, the first column we need to create is for the selected model.
Have you tried the simplest thing - adding :conditions
to the has_many :through
s?
In other words, something like this (in widget.rb):
has_many :people, :through => :widget_groupings, :conditions => { :type => 'Person' }, :source => :grouper, :source_type => 'SentientBeing'
has_many :aliens, :through => :widget_groupings, :conditions => { :type => 'Alien' }, :source => :grouper, :source_type => 'SentientBeing'
JamesDS is correct that a join is needed - but it's not written out here, since the has_many :through
association is already doing it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With