[Rails] Re: Polymorphic, many-to-many, self-referential data model

Josh Susser
Sat, 20 May 2006 17:28:20 -0000

Jason King wrote:
> No matter what I try I''ve been unable to work how to get this to
work with
> the cool ActiveRecord helpers.  I''m not sure if it''s
possible, Josh Susser''s
> blog suggests it is, but damned if I can work it out...

Interesting combination of polymorpic and self-ref with through. I think
this should do it...

-----
create_table :containers do |t|
  t.column :name, :string
end

create_table :chunks do |t|
  t.column :name, :string
end

create_table :ownerships do |t|
  t.column :name, :string
  t.column :owner_id, :integer
  t.column :element_id, :integer
  t.column :element_type, :string
end

class Ownership < ActiveRecord::Base
  # to owner
  belongs_to :owner,  :class_name => "Container",
                      :foreign_key => "owner_id"
  # to elements
  belongs_to :element,    :polymorphic => true
  belongs_to :container,  :class_name => "Container",
                          :foreign_key => "element_id"
  belongs_to :chunk,      :class_name => "Chunk",
                          :foreign_key => "element_id"
end

class Container < ActiveRecord::Base
  # to owner
  has_many :ownings,  :class_name => "Ownership", :as =>
:element
  has_many :owners,   :through => :ownings
  # to elements
  has_many :ownerships
  has_many :containers, :through => :ownerships, :source => :article,
                        :conditions => "ownerships.element_type =
''Container''"
  has_many :chunks,     :through => :ownerships, :source => :book,
                        :conditions => "ownerships.element_type =
''Chunk''"
end

class Chunk < ActiveRecord::Base
  # to owner
  has_many :ownings,  :class_name => "Ownership", :as =>
:element
  has_many :owners,   :through => :ownings
end
-----

I haven''t tested this out, but I''m pretty sure it should do
what you
want, as it''s just a combination of the self-ref and polymorphic
through
patterns. The trick is that you have to disambiguate the two different
associations to containers - one way is as your container, and the other
is as an element. That means you need different names for those
relationship. I chose "owner" to indicate an element''s
container from
the element''s perspective. You also have to use a different name for
the
two kinds of ownerships, containing and contained.

Give it a shot and let me know if it works.  This would be good for a
writeup.

--
Josh Susser