Skip to content

Instantly share code, notes, and snippets.

@blt04
Created June 24, 2011 19:12
Show Gist options
  • Save blt04/1045451 to your computer and use it in GitHub Desktop.
Save blt04/1045451 to your computer and use it in GitHub Desktop.
ActiveRecord self-referential many-to-many relationships with extra attributes
class CreateExampleTables < ActiveRecord::Migration
def self.up
create_table :masters do |t|
t.string :fname
t.string :lname
t.timestamps
end
create_table :master_relations do |t|
t.integer :master_id, :null => false
t.integer :relation_id, :null => false
t.string :relation_type, :null => false
t.timestamps
end
end
def self.down
drop_table :masters
drop_table :master_relations
end
end
# The relationship names could be improved, but this works
# Not sure if it is the most elegant way, but it should allow you to
# store and query relationship types
bt = Master.create(:fname => 'Brandon', :lname => 'Turner')
mt = Master.create(:fname => 'Marcia', :lname => 'Turner')
bt.master_relations.create(:relation => mt, :relation_type => 'Wife')
mt.master_relations.create(:relation => bt, :relation_type => 'Husband')
# All of Brandon's relations, regardless of type
bt.relations
=> [#<Master id: 2, fname: "Marcia", lname: "Turner"]
# Brandon's wives?
bt.relations_by('Wife')
=> [#<Master id: 2, fname: "Marcia", lname: "Turner"]
# Brandon's husbands?
bt.relations_by('Husband')
=> []
# Who is Brandon a husband to?
bt.inverse_relations_by('Husband')
=> [#<Master id: 2, fname: "Marcia", lname: "Turner"]
class Master < ActiveRecord::Base
has_many :master_relations
has_many :inverse_master_relations, :class_name => 'MasterRelation', :foreign_key => :relation_id
has_many :relations, :through => :master_relations
has_many :inverse_relations, :through => :inverse_master_relations, :source => :master
def relations_by(relation_type)
relations.where(:master_relations => {:relation_type => relation_type})
end
def inverse_relations_by(relation_type)
inverse_relations.where(:master_relations => {:relation_type => relation_type})
end
end
class MasterRelation < ActiveRecord::Base
belongs_to :master
belongs_to :relation, :class_name => 'Master'
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment