4 An ActiveRecord plugin for defining self-referential polymorphic associations.
8 Copyright 2007 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file.
12 This plugin lets you define self-referential and double-sided polymorphic associations in your models. It is an extension of <tt>has_many :through</tt>.
14 “Polymorphic” means an association can freely point to any of several unrelated model classes, instead of being tied to one particular class.
19 * double-sided polymorphism
20 * efficient, merged association SELECT
23 * automatic individual and reverse associations
25 And a generator for a tagging system, a common use case.
29 * Rails 1.2.3 or greater
35 To install the Rails plugin, run:
36 script/plugin install svn://rubyforge.org/var/svn/fauna/has_many_polymorphs/trunk
38 There's also a gem version. To install it instead, run:
39 sudo gem install has_many_polymorphs
41 If you are using the gem, make sure to add <tt>require 'has_many_polymorphs'</tt> to <tt>environment.rb</tt>, before Rails::Initializer block.
45 Setup the parent model as so:
47 class Petfood < ActiveRecord::Base
48 has_many_polymorphs :eaters, :from => [:dogs, :cats, :birds]
53 class EatersPetfood < ActiveRecord::Base
55 belongs_to :eater, :polymorphic => true
58 One of the child models:
60 class Dog < ActiveRecord::Base
64 See ActiveRecord::Associations::PolymorphicClassMethods for more configuration options.
66 == Helper methods example
68 petfood = Petfood.find(1)
69 petfood.eaters.map(&:class) # => [Dog, Cat, Cat, Bird]
71 petfood.eaters.push(Cat.create)
72 petfood.eaters << Cat.create
73 petfood.cats.size # => 4
74 petfood.eaters.size # => 6
76 petfood.eaters.delete(petfood.dogs[0])
77 petfood.dogs.size # => 0
78 petfood.eaters.size # => 5
81 petfood.eaters[0].petfoods.include?(petfood) # => true
83 See ActiveRecord::Associations::PolymorphicAssociation for more helper method details.
87 == Double-sided polymorphism
89 Double-sided relationships are defined on the join model:
91 class Devouring < ActiveRecord::Base
92 belongs_to :eater, :polymorphic => true
93 belongs_to :eaten, :polymorphic => true
95 acts_as_double_polymorphic_join(
96 :eaters =>[:dogs, :cats],
97 :eatens => [:cats, :birds]
101 Now, dogs and cats can eat birds and cats. Birds can't eat anything (they aren't <tt>eaters</tt>) and dogs can't be eaten by anything (since they aren't <tt>eatens</tt>). The keys stand for what the models are, not what they do.
103 In this case, each eater/eaten relationship is called a Devouring.
105 See ActiveRecord::Associations::PolymorphicClassMethods for more.
109 Has_many_polymorphs includes a tagging system generator.
111 ./script/generate tagging TaggableModel1 TaggableModel2 [..]
113 You can use the optional flag <tt>--skip-migration</tt> to skip generating a migration (for example, if you are converting from <tt>acts_as_taggable</tt>). You can also use the flag <tt>--self-referential</tt> if you want to be able to tag tags.
115 Tests will be generated, but will not work unless you have at least 2 fixture entries for the first two taggable models. Their ids must be 1 and 2.
119 Some debugging tools are available in <tt>lib/has_many_polymorphs/debugging_tools.rb</tt>.
121 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 <tt>:class_name</tt>, <tt>:foreign_key</tt>, or <tt>:as</tt>. The included tests are a good place to look for examples.
123 Note that because of the way Rails reloads model classes, the plugin can sometimes bog down your development server. Set <tt>config.cache_classes = true</tt> in <tt>config/environments/development.rb</tt> to avoid this.
127 * http://blog.evanweaver.com/pages/code#polymorphs
128 * http://rubyforge.org/forum/forum.php?forum_id=16450