has_many :through polymorphic with STI in the polymorphic target
tables
Hello,
In our data model we have Users that can be members of Schools,
Organizations, etc.
The Schools table uses STI to support Colleges and High Schools,
The has_many code is pretty straightforward, here is the school side
(school_memberships inherits from memberships):
(all the models and schema at the bottom or http://pastie.caboo.se/193409)
class School < ActiveRecord::Base
has_many :school_memberships, :as => :member
has_many :users, :through => :school_memberships
end
Now if I do:
some_school.users it runs the following query:
SELECT users.* FROM users
INNER JOIN memberships ON users.id = memberships.user_id
WHERE ((memberships.member_type = 'School') AND (memberships.member_id
= 3) AND ((memberships.type = 'SchoolMembership')))
The problem here is that there is no need for a
memberships.member_type column, the memberships.type column is
handling the polymorphism of the table. If I add this column in the
migration anyway, it causes a problem because Rails doesn't populate
it reliably (it populates it if you add a user to a school, but not if
you add a school to a user -- some_user.schools << some_school).
My question, then, is how can I get Rails to not use the
memberships.member_type column without overriding the built in
methods?
I looked for people doing this and found some similar things:
Josh Susser - http://blog.hasmanythrough.com/2006/4/3/polymorphic-through,
and
Pratik Naik - http://m.onkey.org/2007/8/14/excuse-me-wtf-is-polymorphs
but they are focused on making polymorphism work at all (i.e. joining
to multiple tables) and my problem seems to stem from having one of
the target tables have STI on it.
Can anyone point me to where to look for anything on this, or to
someone who has done it?
Here's what works and does not work when I keep the membership_type
column in more detail:
a_school.users << a_user
it works perfectly and inserts a SchoolMembership into the memberships
table
#<SchoolMembership id: 1, user_id: 1, type: "SchoolMembership",
member_id: 2, member_type: "School">
(in this case: #<User id: 1, name: "Joseph"> and #<College id: 2,
name: "NYU", type: "College"> )
- here School puts "School" in member_type and "SchoolMembership" in
the type
But, if I do:
a_user.schools << a_school
the SchoolMembership that gets created does not have a member_type:
#<SchoolMembership id: 1, user_id: 1, type: "SchoolMembership",
member_id: 2, member_type: nil>
- User only puts "SchoolMembership" in the type
The Code:
class User < ActiveRecord::Base
has_many :school_memberships
has_many :schools, :through => :school_memberships
end
class School < ActiveRecord::Base
has_many :school_memberships, :as => :member
has_many :users, :through => :school_memberships
end
# Table name: schools