SimplyRichAssociation ===================== This plugin is based on Chad Fowler's Rails Recipe #18 : Self-referential Many-to-Many Relationships in Rails Recipe book. Simplifies self referential many to many relationship. It manages the bidirectional link creation and deletion automatically. == Author Bala Paranj:: bparanj at gmail [dot] com == Current Release The current stable release is v0.1 released on 03-15-2007. == Installation On your Rails' root directory, just type script/plugin install http://sra.rubyforge.org/simply_rich_association == Usage class Person < ActiveRecord::Base has_and_belongs_to_many :friends, :class_name => "Person", :join_table => "friends_people", :association_foreign_key => "friend_id", :foreign_key => "person_id", :after_add => :be_friendly_to_friend, :after_remove => :no_more_mr_nice_guy def be_friendly_to_friend(friend) friend.friends << self unless friend.friends.include?(self) end def no_more_mr_nice_guy(friend) friend.friends.delete(self) rescue nil end end becomes: class Person < ActiveRecord::Base has_self_referential_many_to_many :friends end In the script/console you can see: ~/work/plugins/sra > script/console Loading development environment. >> p1 = Person.create :name => "Chad" => #, new_recordfalse, attributes{"name"=>"Chad", "id"=>48}, new_record_before_savetrue >> p2 = Person.create :name => "Tintin" => #, new_recordfalse, attributes{"name"=>"Tintin", "id"=>49}, new_record_before_savetrue >> p1.friends << p2 => [#, new_recordfalse, friends[#, new_recordfalse, friends[....], attributes{"name"=>"Chad", "id"=>48}, new_record_before_savetrue], attributes{"name"=>"Tintin", "id"=>49}, new_record_before_savetrue] >> p1.friends.size => 1 >> p2.friends.size => 1 --------------------------------------------- It also provides syntactic sugar for ActiveRecord has_many :through macro: For instance if you have a migration as: class Subscription < ActiveRecord::Migration def self.up create_table :subscriptions do |t| t.column :reader_id, :integer t.column :magazine_id, :integer t.column :last_renewal_on, :date t.column :length_in_issues, :integer end create_table :magazines do |t| t.column :title, :string end create_table :readers do |t| t.column :name, :string end end def self.down end end and the models as: class Subscription < ActiveRecord::Base belongs_to :reader belongs_to :magazine end class Reader < ActiveRecord::Base has_many :subscriptions has_many :magazines, :through => :subscriptions end class Magazine < ActiveRecord::Base has_many :subscriptions has_many :readers, :through => :subscriptions end using this plugin, your models become: class Subscription < ActiveRecord::Base belongs_to :reader belongs_to :magazine end class Reader < ActiveRecord::Base has_many_through :magazines, :subscriptions end class Magazine < ActiveRecord::Base has_many_through :readers, :subscriptions end This example is based on Rails Recipe #22, Many-to-Many Relationships with Extra Data of Chad Fowler's Rails Recipes book. ~/work/plugins/test/hmt > script/console Loading development environment. >> m = Magazine.create :title => "Ruby Illustrated" => #, new_recordfalse, attributes{"title"=>"Ruby Illustrated", "id"=>2}, new_record_before_savetrue >> r = Reader.create :name => "TinTin" => #, new_recordfalse, attributes{"name"=>"TinTin", "id"=>2}, new_record_before_savetrue >> s = Subscription.create(:last_renewal_on => Date.today, :length_in_issues => 6) => #>, @new_record=false, @attributes={"last_renewal_on"=>#, "id"=>2, "length_in_issues"=>6, "reader_id"=>nil, "magazine_id"=>nil}> >> m.subscriptions << s => [#>, @new_record=false, @attributes={"last_renewal_on"=>#, "id"=>2, "length_in_issues"=>6, "reader_id"=>nil, "magazine_id"=>2}>] >> r.subscriptions << s => [#>, @new_record=false, @attributes={"last_renewal_on"=>#, "id"=>2, "length_in_issues"=>6, "reader_id"=>2, "magazine_id"=>2}>] >> s.save => true >> m.readers => [#"TinTin", "id"=>"2"}] >> r.magazines => [#"Ruby Illustrated", "id"=>"2"}] >> == Getting help You can always send me an email (bparanj at gmail dot com) if you have any questions. == Bugs/Patches Please report the bugs you find by opening tickets here[https://sra.rubyforge.org/support/newticket] == Special Thanks to: * Chad Fowler for his help during the development of this plugin. * RubyForge (www.rubyforge.org) == Release Information Released under the MIT license.