Joseph Sofaer
2008-May-08 02:21 UTC
has_many :through polymorphic with STI in the polymorphic target tables
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 # # id :integer # name :string # type :string class College < School end class Membership < ActiveRecord::Base belongs_to :user end # Table name: memberships # # id :integer # member_id :integer # member_type :string # type :string class SchoolMembership < Membership belongs_to :school, :foreign_key => :member_id end --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Trevor Squires
2008-May-08 03:04 UTC
Re: has_many :through polymorphic with STI in the polymorphic target tables
Hi, Okay... first of all, if you don''t have a *darn* good reason for using STI on your memberships table then get rid of it. Second of all, you''re missing some things to tell rails about your polymorphism. Take a look at the following code (untested, off the top of my head): class Membership belongs_to :user belongs_to :member, :polymorphic => true end Note - that means that membership belongs to a user (duh!) and to a ''member'' which can be *anything* - School, Business, Club, FluffyKitten - *any* active record object. class User has_many :memberships has_many :schools, :through => :memberships, :source => :member, :source_type => ''School'' has_many :clubs, :through => :memberships, :source => :member, :source_type => ''Club'' has_many :fluffy_kittens, :through => :memberships, :source => :member, :source_type => ''FluffyKitten'' end class School has_many :memberships, :as => :member has_many :users, :through => :memberships end class Club has_many :memberships, :as => :member has_many :users, :through => :memberships end class FluffyKitten ... okay, you get the idea. Basically, if you want to use a polymorphic belongs_to - you have to actually *declare* it as such if you want the free setup of the polymorph_type field. I can understand why you went down your original route - and if you *really* know what you''re doing you can torture ActiveRecord enough to do your bidding. But you''d be fighting the framework and it would be a source of confusion and pain. IMHO, of course. Hope that helps, Trevor On 5/7/08, Joseph Sofaer <joseph.sofaer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > 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 > # > # id :integer > # name :string > # type :string > > > class College < School > end > > > class Membership < ActiveRecord::Base > belongs_to :user > end > > # Table name: memberships > # > # id :integer > # member_id :integer > # member_type :string > # type :string > > > class SchoolMembership < Membership > belongs_to :school, :foreign_key => :member_id > end > > >-- -- Trevor Squires http://somethinglearned.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Joseph Sofaer
2008-May-08 20:08 UTC
Re: has_many :through polymorphic with STI in the polymorphic target tables
Hi Trevor, Thanks a lot for your reply, I think I''ve tried it that way and still had troubles. It seems like the STI in the memberships table is fine and works smoothly - the STI in the target table is the headache. The type column in memberships is not the issue, it''s the member_type column that doesn''t seem to work correctly. It''s really interesting that actually I don''t think you need the :polymorphic => true part. I''ve put that in my membership model before and it doesn''t seem to change anything (if I hit ''undo'' once it pops back in so I''ve been playing with it a lot). In fact if you read through the comments on Josh Susser''s has_many through blog post about it someone mentions that (it is however 2 years old): François Simond – 2006-04-22 15:25:09 : "While experimenting i just found that belongs_to :publication, :polymorphic => true has no effect. You can use belongs_to :foobar, :polymorphic => true or simply delete the line, it does not change anything." Josh Susser – 2006-04-24 08:22:22: "@François: Wow, that''s odd. But some of that association code is pretty bizarre." So really the trouble is that the target table uses STI and the School model wants a member_type = "School" in the memberships table in addition to having type = "SchoolMembership" - but the User model only knows to put: type = "SchoolMembership." It would be amazing if School would just look for type "SchoolMembership" instead of both which is redundant. I thought there might be some option that I could add in the school class to get it to do that. I could make a before_save filter or something like that to make it work but if I go down that road I feel like I may as well go back to the messier/less-DRY stuff I had before and not re-write my model files with the more elegant (but flawed) new solution. Thanks a lot for your reply, Much appreciated, All the best, Joseph On May 7, 8:04 pm, "Trevor Squires" <tre...-k8q5a0yEZAgS+FvcfC7Uqw@public.gmane.org> wrote:> Hi, > > Okay... first of all, if you don''t have a *darn* good reason for using > STI on your memberships table then get rid of it. > > Second of all, you''re missing some things to tell rails about your > polymorphism. Take a look at the following code (untested, off the > top of my head): > > class Membership > belongs_to :user > belongs_to :member, :polymorphic => true > end > > Note - that means that membership belongs to a user (duh!) and to a > ''member'' which can be *anything* - School, Business, Club, > FluffyKitten - *any* active record object. > > class User > has_many :memberships > has_many :schools, :through => :memberships, :source => :member, > :source_type => ''School'' > has_many :clubs, :through => :memberships, :source => :member, > :source_type => ''Club'' > has_many :fluffy_kittens, :through => :memberships, :source => > :member, :source_type => ''FluffyKitten'' > end > > class School > has_many :memberships, :as => :member > has_many :users, :through => :memberships > end > > class Club > has_many :memberships, :as => :member > has_many :users, :through => :memberships > end > > class FluffyKitten ... okay, you get the idea. > > Basically, if you want to use a polymorphic belongs_to - you have to > actually *declare* it as such if you want the free setup of the > polymorph_type field. > > I can understand why you went down your original route - and if you > *really* know what you''re doing you can torture ActiveRecord enough to > do your bidding. But you''d be fighting the framework and it would be > a source of confusion and pain. > > IMHO, of course. > > Hope that helps, > Trevor > > On 5/7/08, Joseph Sofaer <joseph.sof...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > > > > 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 orhttp://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 > > # > > # id :integer > > # name :string > > # type :string > > > class College < School > > end > > > class Membership < ActiveRecord::Base > > belongs_to :user > > end > > > # Table name: memberships > > # > > # id :integer > > # member_id :integer > > # member_type :string > > # type :string > > > class SchoolMembership < Membership > > belongs_to :school, :foreign_key => :member_id > > end > > -- > -- > Trevor Squireshttp://somethinglearned.com--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Joseph Sofaer
2008-May-08 20:09 UTC
Re: has_many :through polymorphic with STI in the polymorphic target tables
Hi Trevor, Thanks a lot for your reply, I think I''ve tried it that way and still had troubles. It seems like the STI in the memberships table is fine and works smoothly - the STI in the target table is the headache. The type column in memberships is not the issue, it''s the member_type column that doesn''t seem to work correctly. It''s really interesting that actually I don''t think you need the :polymorphic => true part. I''ve put that in my membership model before and it doesn''t seem to change anything (if I hit ''undo'' once it pops back in so I''ve been playing with it a lot). In fact if you read through the comments on Josh Susser''s has_many through blog post about it someone mentions that (it is however 2 years old): François Simond – 2006-04-22 15:25:09 : "While experimenting i just found that belongs_to :publication, :polymorphic => true has no effect. You can use belongs_to :foobar, :polymorphic => true or simply delete the line, it does not change anything." Josh Susser – 2006-04-24 08:22:22: "@François: Wow, that''s odd. But some of that association code is pretty bizarre." So really the trouble is that the target table uses STI and the School model wants a member_type = "School" in the memberships table in addition to having type = "SchoolMembership" - but the User model only knows to put: type = "SchoolMembership." It would be amazing if School would just look for type "SchoolMembership" instead of both which is redundant. I thought there might be some option that I could add in the school class to get it to do that. I could make a before_save filter or something like that to make it work but if I go down that road I feel like I may as well go back to the messier/less-DRY stuff I had before and not re-write my model files with the more elegant (but flawed) new solution. Thanks a lot for your reply, Much appreciated, All the best, Joseph On May 7, 8:04 pm, "Trevor Squires" <tre...-k8q5a0yEZAgS+FvcfC7Uqw@public.gmane.org> wrote:> Hi, > > Okay... first of all, if you don''t have a *darn* good reason for using > STI on your memberships table then get rid of it. > > Second of all, you''re missing some things to tell rails about your > polymorphism. Take a look at the following code (untested, off the > top of my head): > > class Membership > belongs_to :user > belongs_to :member, :polymorphic => true > end > > Note - that means that membership belongs to a user (duh!) and to a > ''member'' which can be *anything* - School, Business, Club, > FluffyKitten - *any* active record object. > > class User > has_many :memberships > has_many :schools, :through => :memberships, :source => :member, > :source_type => ''School'' > has_many :clubs, :through => :memberships, :source => :member, > :source_type => ''Club'' > has_many :fluffy_kittens, :through => :memberships, :source => > :member, :source_type => ''FluffyKitten'' > end > > class School > has_many :memberships, :as => :member > has_many :users, :through => :memberships > end > > class Club > has_many :memberships, :as => :member > has_many :users, :through => :memberships > end > > class FluffyKitten ... okay, you get the idea. > > Basically, if you want to use a polymorphic belongs_to - you have to > actually *declare* it as such if you want the free setup of the > polymorph_type field. > > I can understand why you went down your original route - and if you > *really* know what you''re doing you can torture ActiveRecord enough to > do your bidding. But you''d be fighting the framework and it would be > a source of confusion and pain. > > IMHO, of course. > > Hope that helps, > Trevor > > On 5/7/08, Joseph Sofaer <joseph.sof...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > > > > 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 orhttp://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 > > # > > # id :integer > > # name :string > > # type :string > > > class College < School > > end > > > class Membership < ActiveRecord::Base > > belongs_to :user > > end > > > # Table name: memberships > > # > > # id :integer > > # member_id :integer > > # member_type :string > > # type :string > > > class SchoolMembership < Membership > > belongs_to :school, :foreign_key => :member_id > > end > > -- > -- > Trevor Squireshttp://somethinglearned.com--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Trevor Squires
2008-May-08 21:20 UTC
Re: has_many :through polymorphic with STI in the polymorphic target tables
Joseph, okay, in the nicest possible way, and bearing in mind that all I have to go on is the information you presented about your code... you''re doing it wrong. You quoted: http://blog.hasmanythrough.com/2006/4/3/polymorphic-through I wrote the patch that added the :source_type option to Rails in response to that post. So... a) the post is out of date - I fixed what he was talking about, and b) I really do know what I''m talking about here. The reason adding :polymorphic => true makes no difference is that you''ve written your code to ignore it (this is why I gave you full examples). You have: class User < ActiveRecord::Base has_many :school_memberships has_many :schools, :through => :school_memberships end class Membership < ActiveRecord::Base belongs_to :user end class SchoolMembership < Membership belongs_to :school, :foreign_key => :member_id belongs_to :user end And you''ve said that "a_user.schools << a_school" doesn''t fill in member_type. Of course it doesn''t. Instead it''s doing exactly what you told it to do: * create a SchoolMembership * assign a_user to school_membership.user ** which assigns a_user.id to school_membership.user_id * assign a_school to school_membership.school ** which assigns a_school.id to school_membership.membership_id Go back and look at the code I sent you. With my code, this is what "a_user.schools << a_school" does: * create a Membership * assign a_user to membership.user ** which assigns a_user.id to membership.user_id * assign a_school to membership.member ** which assigns a_school.id to membership.member_id ** and which assigns a_school.class.name to membership.member_type Regards, Trevor On 5/8/08, Joseph Sofaer <joseph.sofaer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > Hi Trevor, > Thanks a lot for your reply, > I think I''ve tried it that way and still had troubles. > It seems like the STI in the memberships table is fine and works > smoothly - the STI in the target table is the headache. > The type column in memberships is not the issue, > it''s the member_type column that doesn''t seem to work correctly. > > It''s really interesting that actually I don''t think you need the > :polymorphic => true part. > I''ve put that in my membership model before and it doesn''t seem to > change anything (if I hit ''undo'' once it pops back in so I''ve been > playing with it a lot). > In fact if you read through the comments on Josh Susser''s has_many > through blog post about it someone mentions that (it is however 2 > years > old): > > François Simond – 2006-04-22 15:25:09 : > "While experimenting i just found that belongs_to :publication, > :polymorphic => true has no effect. > You can use belongs_to :foobar, :polymorphic => true or simply delete > the line, it does not change anything." > > Josh Susser – 2006-04-24 08:22:22: > "@François: Wow, that''s odd. But some of that association code is > pretty bizarre." > > > So really the trouble is that the target table uses STI and the School > model wants a member_type = "School" in the memberships table in > addition to having type = "SchoolMembership" - but the User model only > knows to put: type = "SchoolMembership." > It would be amazing if School would just look for type > "SchoolMembership" instead of both which is redundant. > I thought there might be some option that I could add in the school > class to get it to do that. > > I could make a before_save filter or something like that to make it > work but if I go down that road I feel like I may as well go back to > the messier/less-DRY stuff I had before and not re-write my model > files with the more elegant (but flawed) new solution. > > Thanks a lot for your reply, > Much appreciated, > All the best, > Joseph > > > > On May 7, 8:04 pm, "Trevor Squires" <tre...-k8q5a0yEZAgS+FvcfC7Uqw@public.gmane.org> wrote: > > Hi, > > > > Okay... first of all, if you don''t have a *darn* good reason for using > > STI on your memberships table then get rid of it. > > > > Second of all, you''re missing some things to tell rails about your > > polymorphism. Take a look at the following code (untested, off the > > top of my head): > > > > class Membership > > belongs_to :user > > belongs_to :member, :polymorphic => true > > end > > > > Note - that means that membership belongs to a user (duh!) and to a > > ''member'' which can be *anything* - School, Business, Club, > > FluffyKitten - *any* active record object. > > > > class User > > has_many :memberships > > has_many :schools, :through => :memberships, :source => :member, > > :source_type => ''School'' > > has_many :clubs, :through => :memberships, :source => :member, > > :source_type => ''Club'' > > has_many :fluffy_kittens, :through => :memberships, :source => > > :member, :source_type => ''FluffyKitten'' > > end > > > > class School > > has_many :memberships, :as => :member > > has_many :users, :through => :memberships > > end > > > > class Club > > has_many :memberships, :as => :member > > has_many :users, :through => :memberships > > end > > > > class FluffyKitten ... okay, you get the idea. > > > > Basically, if you want to use a polymorphic belongs_to - you have to > > actually *declare* it as such if you want the free setup of the > > polymorph_type field. > > > > I can understand why you went down your original route - and if you > > *really* know what you''re doing you can torture ActiveRecord enough to > > do your bidding. But you''d be fighting the framework and it would be > > a source of confusion and pain. > > > > IMHO, of course. > > > > Hope that helps, > > Trevor > > > > > On 5/7/08, Joseph Sofaer <joseph.sof...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > > > > > > > > > > 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 orhttp://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 > > > # > > > # id :integer > > > # name :string > > > # type :string > > > > > class College < School > > > end > > > > > class Membership < ActiveRecord::Base > > > belongs_to :user > > > end > > > > > # Table name: memberships > > > # > > > # id :integer > > > # member_id :integer > > > # member_type :string > > > # type :string > > > > > class SchoolMembership < Membership > > > belongs_to :school, :foreign_key => :member_id > > > end > > > > -- > > > -- > > Trevor Squireshttp://somethinglearned.com > > > >-- -- Trevor Squires http://somethinglearned.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Joseph Sofaer
2008-May-09 01:16 UTC
Re: has_many :through polymorphic with STI in the polymorphic target tables
Hi Trevor, Thanks a lot for the clarification. I think I have it now. The :source_type was the piece that I wasn''t getting. Indeed I was a bit worried about the 2 year old aspect of those blog entries. Before I went over the edge with the SchoolMembership class we had: class User < ActiveRecord::Base has_many :memberships has_many :schools, :through => :memberships, :conditions => "memberships.member_type = ''College'' OR memberships.member_of_type ''HighSchool''" end That was not pretty and we couldn''t use built in methods, etc, so it felt wrong. Your active record patch is awesome and thank you for getting me back on track. All the best, Joseph --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---