Ruby on Rails
HowToUseManyToManyAgainstASingleTable

see also HowToCreateASelfReferentialManyToManyRelationship

Let’s say you need to model a node graph, something like this:

So you create a database like the following:


create_table "nodes" do |t|    
  t.column :name,  :string
end 

create_table "nodelinks", :id => false do |t|
  t.column :source_id,      :integer, :null => false
  t.column :destination_id, :integer, :null => false
end

A node (source) can be connected to any other node (destinations).


Depending on directionality and how you store it in the database, you can simply do

has_and_belongs_to_many :nodes, 
:join_table => 'nodelink', 
:association_foreign_key => 'destination_id', 
:foreign_key => 'source_id'

This assumes that nodelink contains both a row with “Node B connects to Node C” and one with “Node C connects to Node B” in order to model the seemingly non-directional graph.

—Jakob S


To create a directional version using the above tables:


class Node < ActiveRecord::Base
  has_and_belongs_to_many :linked_from,
    :class_name => 'Node',
    :join_table => 'nodelink',
    :association_foreign_key => 'source_id',
    :foreign_key => 'destination_id'

  has_and_belongs_to_many :linked_to,
    :class_name => 'Node',
    :join_table => 'nodelink',
    :association_foreign_key => 'destination_id',
    :foreign_key => 'source_id'
end

Note that the ordering of source_id versus destination_id is what makes the difference between the incoming links versus the outgoing links.

—Phrogz


One might argue also that this is contrived, and you should create a real Edge class. This way when you finally realise “whoops, I need to colour the edges of the graph”, you have somewhere to store that property.

—AC


How would you go about converting the edges into a full blown model with edge colours and weights?