Fritz Anderson
2009-Aug-07 17:47 UTC
Polymorphic belongs_to with :class_name => abstract class
SUMMARY: How do I assign objects, of different subclasses of an abstract class, to a belongs_to relation? I had the following class hierarchy: Location < ActiveRecord::Base Address < Location Building < Location and a class Person with these relationships: has_one :address, :dependent => :destroy belongs_to :building Location is backed by table "locations," and Person by "People." I had to refactor to insert an abstract class between Location and Building: Location < ActiveRecord::Base Address < Location SharedLocation < Location Building < SharedLocation DeletedLocation < SharedLocation I now want Person#building to refer to either a Building or a DeletedLocation. Refactoring the foreign key and accessor would be a major pain. I changed the relation for Person#building to: belongs_to :building, :class_name => ''SharedLocation'', :foreign_key => ''building_id'' (:foreign_key because I got a deprecation warning on specifying :class_name without one.) I also moved has_many :people, :dependent => :nullify from Building to SharedLocation. In the course of flailing about for a solution, I added ":foreign_key => ''building_id''", but I don''t know what I''m doing. I ran my unit tests for setting the relation, and am now seeing failures/errors, all of which seem to boil down to this: Attempting person = Building.new(...) gets an AssociationTypeMismatch, "SharedLocation expected, got Building." How do I make belongs_to relations polymorphic? Rails 2.3.2 ruby 1.8.7 (2008-08-11 patchlevel 72) [universal-darwin10.0] -- Posted via http://www.ruby-forum.com/.
Ilan Berci
2009-Aug-07 18:58 UTC
Re: Polymorphic belongs_to with :class_name => abstract class
Fritz Anderson wrote:> SUMMARY: How do I assign objects, of different subclasses of an abstract > class, to a belongs_to relation? > > I had the following class hierarchy: > > Location < ActiveRecord::Base > Address < Location > Building < Location > > and a class Person with these relationships: > has_one :address, :dependent => :destroy > belongs_to :building > > Location is backed by table "locations," and Person by "People." > > I had to refactor to insert an abstract class between Location and > Building: > > Location < ActiveRecord::Base > Address < Location > SharedLocation < Location > Building < SharedLocation > DeletedLocation < SharedLocation > > I now want Person#building to refer to either a Building or a > DeletedLocation. Refactoring the foreign key and accessor would be a > major pain. > > I changed the relation for Person#building to: > belongs_to :building, :class_name => ''SharedLocation'', > :foreign_key => ''building_id'' > > (:foreign_key because I got a deprecation warning on specifying > :class_name without one.) > > I also moved > has_many :people, :dependent => :nullify > from Building to SharedLocation. In the course of flailing about for a > solution, I added ":foreign_key => ''building_id''", but I don''t know what > I''m doing. > > I ran my unit tests for setting the relation, and am now seeing > failures/errors, all of which seem to boil down to this: Attempting > person = Building.new(...) > gets an AssociationTypeMismatch, "SharedLocation expected, got > Building." > > How do I make belongs_to relations polymorphic? > > Rails 2.3.2 > ruby 1.8.7 (2008-08-11 patchlevel 72) [universal-darwin10.0]First off, I disagree with your use of polymorphism in this problem domain. You could keep location a top level class along with a status field which could simply hold the values ''building'', or ''deleted''. Choose sub classing for changes and/or additions to functionality vs changes and/or additions to state. Anyways, disregarding the above.. take a look at this excellent podcast by Bates that explains it as well as any.. http://railscasts.com/episodes/154-polymorphic-association hth ilan -- Posted via http://www.ruby-forum.com/.
Fritz Anderson
2009-Aug-07 20:50 UTC
Re: Polymorphic belongs_to with :class_name => abstract clas
Ilan Berci wrote:> First off, I disagree with your use of polymorphism in this problem > domain. You could keep location a top level class along with a status > field which could simply hold the values ''building'', or ''deleted''. > Choose sub classing for changes and/or additions to functionality vs > changes and/or additions to state.In this case, trying to distinguish Building from DeletedLocation would have required a lot of branches and conditionals on that one flag, and I follow the rule-of-thumb that if the program has to change behavior based on a non-displayed state variable, you have to consider refactoring the classes.> Anyways, disregarding the above.. take a look at this excellent podcast > by Bates that explains it as well as any.. > http://railscasts.com/episodes/154-polymorphic-associationThis did help, thank you. What misled me was that I''d hoped setting an ActiveRecord relation could "just work" in the way other object references do. Obviously, on reflection, the engine has to be assured that the DB plumbing is in place. So I added a building_type column to Person, changed Person''s belongs_to line to belongs_to :building, :polymorphic => true and SharedLocation''s has_many line to has_many :people, :dependent => :nullify, :as => :building Thanks again. — F -- Posted via http://www.ruby-forum.com/.