directed double-polymorphic associations

In a frenzy of Bluetooth-enabled coding from the local diner, I have implemented double polymorphic associations in the has_many_polymorphs plugin. This lets you create a multi-class directed graph in ActiveRecord with great ease.

show, don’t tell

For example, say we wanted to model glue. We want to be able to glue PopsicleSticks and Leaves to themselves, but also to Paper. We will make a join model called Adhesion for this:

class Adhesion < ActiveRecord::Base
  belongs_to :glue_receiver, :polymorphic => true
  belongs_to :glue_applier, :polymorphic => true

  acts_as_double_polymorphic_join :glue_receivers =>
        [:popsicle_sticks, :leaves, :papers],
                                  :glue_appliers =>
        [:popsicle_sticks, :leaves]

This means that a PopsicleStick will have a glue_receivers polymorphic collection that can accept anything in the :glue_receivers list, above. A Paper, though, will not have a .glue_receivers method. It will have a .glue_appliers method, but it is not itself a :glue_applier. This is tricky. Just remember that the lists in the acts_as call are the types of children for that relationship, not the types of parents.

Also, using the individual typed collections (e.g. PopsicleStick#leaves) will always get you the children that belong to the record, instead of the parents that own the record. In this case it will fetch the Leaves from a PopsicleStick object’s .glue_receivers.

warning! class-reloading laser in use!

The API is a little different because there is no parent class that can act as a controller. Things are instead centralized in the join model.

This means that you have to reference the join class (either with load(), by evaluating its bare class name, or another way) before the associations will be injected into the “real” classes. Rails’ selective reloading in the development environment can lead to trouble—a modified class will get reloaded and forget its relationship to the join. Keep this in mind.

crazy clown collections

Combining this with the other plugin features leads to controlled chaos. Self-referential directed double-polymorphic namespaced STI associations are (at least according to my tests) fully supported.

Please try it out and let me know if you have trouble. I really appreciate the filing of bugs.