• Stars
    star
    202
  • Rank 193,691 (Top 4 %)
  • Language
    Ruby
  • License
    Academic Free Lic...
  • Created over 16 years ago
  • Updated about 13 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

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

Has_many_polymorphs

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

DEPRECATED¶ ↑

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://github.com/fauna/has_many_polymorphs.git

There’s also a gem version. To install it instead, run:

sudo gem install has_many_polymorphs

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

Configuration¶ ↑

Setup the parent model as so:

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

The join model:

class GuestsKennel < ActiveRecord::Base
  belongs_to :kennel
  belongs_to :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
    create_table :guests_kennels do |t|
      t.references :guest, :polymorphic => true
      t.references :kennel
    end
  end

  def self.down
    drop_table :guests_kennels
  end
end

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

Helper methods example¶ ↑

>> k = Kennel.find(1)
#<Kennel id: 1, name: "Happy Paws">
>> k.guests.map(&:class)
[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
#<Dog id: 3, name: "Rover">
>> d.kennels
[#<Kennel id: 1, name: "Happy Paws">]

>> 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
  belongs_to :guest, :polymorphic => true
  belongs_to :eaten, :polymorphic => true

  acts_as_double_polymorphic_join(
    :guests =>[:dogs, :cats],
    :eatens => [:cats, :birds]
  )
end

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
  end
end

See ActiveRecord::Associations::PolymorphicClassMethods for more.

Tagging generator¶ ↑

Has_many_polymorphs 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 has_many_polymorphs 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")
#<Dog id: 3, name: "Rover">
>> d.tag_list
""
>> d.tag_with "fierce loud"
#<Dog id: 3, name: "Rover">
>> d.tag_list
"fierce loud"
>> c = Cat.create(:name => "Chloe")
#<Cat id: 1, name: "Chloe">
>> c.tag_with "fierce cute"
#<Cat id: 1, name: "Chloe">
>> c.tag_list
"cute fierce"
>> Tag.find_by_name("fierce").taggables
[#<Cat id: 1, name: "Chloe">, #<Dog id: 3, name: "Rover">]

The generator accepts the optional flag --skip-migration to skip generating a migration (for example, if you are converting from acts_as_taggable). 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/has_many_polymorphs/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 :class_name, :foreign_key, 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¶ ↑

More Repositories

1

bleak_house

A Ruby library for finding memory leaks
Ruby
189
star
2

ultrasphinx

Ruby on Rails configurator and client to the Sphinx full text search engine
Ruby
170
star
3

mongrel

Mongrel
Ruby
144
star
4

peep

A heap inspector for live memcached instances.
Ruby
104
star
5

echoe

A Rubygems packaging tool that provides Rake tasks for documentation, extension compiling, testing, and deployment
Ruby
82
star
6

interlock

A Rails plugin for maintainable and high-efficiency caching
Ruby
75
star
7

ccsv

A pure-C CSV parser for Ruby
Ruby
64
star
8

raspell

A Ruby binding for the Aspell spelling checker
C
59
star
9

sweeper

A Ruby script to automatically tag your music collection with metadata from Last.fm
Ruby
32
star
10

thrift-rb

Ruby bindings for Thrift, with patches.
Ruby
18
star
11

allison

A modern, pretty RDoc template
Ruby
11
star
12

sinatra-jar

Sample monolithic dependency-free Sinatra JAR
Ruby
11
star
13

heroku-hello-world-tests

Ruby
9
star
14

kirby

A super-clean IRC bot with sandboxed Ruby evaluation, repository watching, and link-logging to del.icio.us
Ruby
9
star
15

benchmark_unit

Machine-independent benchmark assertions for your Ruby unit tests
Ruby
7
star
16

fftw3

Gem version of T. Horinouchi's ruby-fftw3.
C
7
star
17

rv

A little init.d system for running Camping apps
Ruby
6
star
18

twist

A Ruby script for logging your system events to Twitter
Ruby
6
star
19

mysqlconfs

MySQL configuration examples
5
star
20

charm_http

A parallel EC2 driver for running the hummingbird HTTP load testing tool against Heroku.
Ruby
4
star
21

shadow

A zero-configuration RESTful ActiveRecord server
Ruby
3
star
22

autobench-grapher

Ruby
2
star
23

wordpress_importer

Script that can import a homegrown blog into WXR format for WordPress.com.
Ruby
1
star
24

cloudbur.st

Cloudbur.st static assets
HTML
1
star
25

js-node

JavaScript
1
star
26

bax

A hacky blog engine that runs via recursive SSI includes
Ruby
1
star
27

scala-finagle

Scala
1
star
28

search_benchmark

Ruby
1
star
29

stub

A stub gem, including C extension.
Ruby
1
star