Every repository with this icon (
Every repository with this icon (
Run the following if you haven't already:
gem sources -a http://gems.github.com
Install the gem(s):
sudo gem install sam-dm-core
Simulating polymorphic associations
DataMapper doesn’t support polymorphic associations (associations with one side pointed at an STI subclass) but you can fake it by simulating STI by putting common properties and the association in a base module that you include.
This won’t work:
# This won't work. Don't try this or you will make DataMapper cry.
class FooBase
include DataMapper::Resource
property :id, Serial # primary key
property :some_common_property, String
property :type, Discriminator # enables STI
belongs_to :bar
end
class FooSubclassA < FooBase
property :some_property_only_subclass_a_has, String
end
class FooSubclassB < FooBase
property :some_property_only_subclass_b_has, Integer
end
class Bar
include DataMapper::Resource
has n, :foo_subclass_as
has n, :foo_subclass_bs
end
This looks like a perfectly reasonable thing to do, but the moment you try to access Bar#foo_subclass_as or Bar#foo_subclass_bs, it’ll fail with a long ugly backtrace.
What you can do, however, is give up STI, keep its benefits, and make the associations work with something like this:
module FooBase # NOTE: it's a Module, _not_ a Class
def self.included(other)
other.class_eval <<-EOS
property :id, Serial
property :some_common_property, String
belongs_to :bar
EOS
end
end
class FooSubclassA # NOTE: not a subclass of anything now
include DataMapper::Resource
include FooBase
property :some_property_only_subclass_a_has, String
end
class FooSubclassB # NOTE: not a subclass of anything now
include DataMapper::Resource
include FooBase
property :some_property_only_subclass_b_has, Integer
end
class Bar
include DataMapper::Resource
has n, :foo_subclass_as
has n, :foo_subclass_bs
end
FooSubclassA and FooSubclassB are no longer formally related, in the sense of having a common ancestor class (apart from Object, but you know what I mean). They are stored in separate tables in the database, whereas STI would by definition keep them in the same table. However, they are guaranteed to have the common properties defined in FooBase, which becomes a kind of de facto superclass for them, and more importantly your associations now work.
You can take this even further. dkubb has suggested that you create a base module with properties such as your models’ primary key and magic timestamps. In other words, you get the benefits of STI (a guarantee of certain properties with one central definition for them) without the drawbacks.





