Skip to content
6twenty edited this page Feb 6, 2011 · 15 revisions

Welcome to the discussion on implementing polymorphism for DataMapper. Please comment, update, edit if you’d like to add stuff.

Example

As an example, we’ll use the old blog articles with comments and tags. Comments is the basic case for polymorphism. Tags is the complex via through.

Schema

A table that implements polymorphism should have 2 additional fields to facilitate the polymorphism.


property :<interface_name>_class, Class  #=> requires a custom Data type
property :<interface_name>_id,    Integer

API


class Post
  include DataMapper::Resource

  has n, :comments, :via => :commentable
end

class Comment
  include DataMapper::Resource

  is :polymorphic, :commentable
end

:polymorphic => true

Sets up the interface and attaches it to the class. The interface attaches the required two properties to the class class_id and id.

It also registers itself as an available polymorphic interface to the class.

Installs the Klass.commentables and Klass#commentable methods

has n … :as => :

This is where the real work is done. Currently the idea for polymorphism is to setup a belong_to association on the polymorphic side, and a has n on the owning side. The has with :as option would set these up on each class. In our comment example, when


has n, :comments, :as => :commentable

is called in the Post class these associations would be set up.


Post.has n, :comments, :child_key => [:commentable_id], :conditions => {:commentable_class => Post}

Comment.belongs_to :post, :child_key => [:commentable_id], :local_conditions => { :commentable_class => Post }

By implementing polymorphism using existing associations, a great deal of flexibility should result.

Comment.commentables

What goes here

Comment#commentable

What goes here

Through assocaitions

Example

In addition to the Post class above.



#Reopen Post from before
class Post
  has n, :taggings,    :via => :taggable

  has n, :tags => :taggings
end

class Tagging
  include DataMapper::Resource

  is :polymorphic, :taggable
  belongs_to :tag
end

class Tag
  include DataMapper::Resource

  has n, :taggings
end

The basic polymorphic stuff is setup on on the Tagging model. Then tags are associated through taggings.

So in posts you can have post.tags and get all the tags assocaited with the post.

The tricky part is when going the other way. For example. How does loading work with something like this:


tag.taggings.each{|t| puts t.taggable } 

Need a PolymorphicCollection that is a collection of collections.

Clone this wiki locally