Need help with has_many_polymorphs?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

201 Stars 61 Forks Academic Free License v3.0 235 Commits 15 Opened issues


An ActiveRecord plugin for self-referential and double-sided polymorphic associations.

Services available


Need anything else?

Contributors list


An ActiveRecord plugin for self-referential and double-sided polymorphic associations.


No replacement.

== License

Copyright 2006-2008 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file.

The public certificate for the gem is here[].

If you use this software, please {make a donation}[], or {recommend Evan}[] at Working with Rails.

== Description

This plugin lets you define self-referential and double-sided polymorphic associations in your models. It is an extension of has_many :through.

“Polymorphic” means an association can freely point to any of several unrelated model classes, instead of being tied to one particular class.

== Features

  • self-references
  • double-sided polymorphism
  • efficient database usage
  • STI support
  • namespace support
  • automatic individual and reverse associations

The plugin also includes a generator for a tagging system, a common use case (see below).

== Requirements

  • Rails 2.2.2 or greater

= Usage

== Installation

To install the Rails plugin, run: script/plugin install git://

There's also a gem version. To install it instead, run: sudo gem install hasmanypolymorphs

If you are using the gem, make sure to add require 'hasmanypolymorphs' to environment.rb, before Rails::Initializer block.

== Configuration

Setup the parent model as so:

class Kennel < ActiveRecord::Base hasmanypolymorphs :guests, :from => [:dogs, :cats, :birds] end

The join model:

class GuestsKennel < ActiveRecord::Base belongsto :kennel belongsto :guest, :polymorphic => true end

One of the child models:

class Dog < ActiveRecord::Base # nothing end

For your parent and child models, you don't need any special fields in your migration. For the join model (GuestsKennel), use a migration like so:

class CreateGuestsKennels < ActiveRecord::Migration def self.up createtable :guestskennels do |t| t.references :guest, :polymorphic => true t.references :kennel end end

def self.down
  drop_table :guests_kennels


See ActiveRecord::Associations::PolymorphicClassMethods for more configuration options.

== Helper methods example

k = Kennel.find(1) # [Dog, Cat, Cat, Bird]

k.guests.push(Cat.create); k.cats.size 3 k.guests << Cat.create; k.cats.size 4 k.guests.size 6

d = k.dogs.first # d.kennels [#]

k.guests.delete(d); k.dogs.size 0 k.guests.size 5

Note that the parent method is always plural, even if there is only one parent (Dog#kennels, not Dog#kennel).

See ActiveRecord::Associations::PolymorphicAssociation for more helper method details.

= Extras

== Double-sided polymorphism

Double-sided relationships are defined on the join model:

class Devouring < ActiveRecord::Base belongsto :guest, :polymorphic => true belongsto :eaten, :polymorphic => true

  :guests =>[:dogs, :cats],
  :eatens => [:cats, :birds]


Now, dogs and cats can eat birds and cats. Birds can't eat anything (they aren't guests) and dogs can't be eaten by anything (since they aren't eatens). The keys stand for what the models are, not what they do.

In this case, each guest/eaten relationship is called a Devouring.

In your migration, you need to declare both sides as polymorphic:

class CreateDevourings < ActiveRecord::Migration def self.up create_table :devourings do |t| t.references :guest, :polymorphic => true t.references :eaten, :polymorphic => true end end

def self.down
  drop_table :devourings


See ActiveRecord::Associations::PolymorphicClassMethods for more.

== Tagging generator

Hasmanypolymorphs includes a tagging system generator. Run: script/generate tagging Dog Cat [...MoreModels...]

This adds a migration and new Tag and Tagging models in app/models. It configures Tag with an appropriate hasmanypolymorphs call against the models you list at the command line. It also adds the file lib/tagging_extensions.rb and requires it in environment.rb.

Tests will also be generated.

Once you've run the generator, you can tag records as follows:

d = Dog.create(:name => "Rover") # d.taglist "" d.tagwith "fierce loud" # d.taglist "fierce loud" c = Cat.create(:name => "Chloe") # c.tagwith "fierce cute" # c.taglist "cute fierce" Tag.findby_name("fierce").taggables [#, #]

The generator accepts the optional flag --skip-migration to skip generating a migration (for example, if you are converting from actsastaggable). It also accepts the flag --self-referential if you want to be able to tag tags.

See ActiveRecord::Base::TaggingExtensions, Tag, and Tagging for more.

== Troubleshooting

Some debugging tools are available in lib/hasmanypolymorphs/debugging_tools.rb.

If you are having trouble, think very carefully about how your model classes, key columns, and table names relate. You may have to explicitly specify options on your join model such as :classname, :foreignkey, or :as. The included tests are a good place to look for examples.

Note that because of the way Rails reloads model classes, the plugin can sometimes bog down your development server. Set config.cache_classes = true in config/environments/development.rb to avoid this.

== Reporting problems

The support forum is here[].

Patches and contributions are very welcome. Please note that contributors are required to assign copyright for their additions to Cloudburst, LLC.

== Further resources


We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.