mshafrir
mshafrir

Reputation: 5220

In Rails, how can I make ActiveRecord associations for two models that reference each other in different ways?

I'm using Rails 3.1. I have a model Tree and a model TreeNode, and I've set up a has_many/belongs_to association between Tree and TreeNodes.

# The initial models and associations.

class Tree < ActiveRecord::Base
  has_many :tree_nodes
end

class TreeNode < ActiveRecord::Base
  belongs_to :tree
end

I want to add the concept of a root node, which isn't necessarily the node that was created first. I can't implicitly determine the root node through created_date, primary key (id), or an order (since there isn't a concept of order with nodes). I'm trying to wrap my head around how to set up this association in Rails.

I started off by adding a root_node column with a foreign key on the Tree table, but my Active Record association would then be Tree belongs_to Node and Node has_one Tree. This is because the class that has the foreign key should have the "belongs_to" association, and the other class should have the "has_one" association. This doesn't sound right to me.

# This code didn't work.

class Tree < ActiveRecord::Base
  has_many :script_steps
  belongs_to :root_tree_node, :class => 'TreeNode'
end

class TreeNode < ActiveRecord::Base
  belongs_to :tree
  has_one :tree
end

I also tried creating a join table with has_one :through, but the associations wouldn't work either.

# This code didn't work.

class Tree < ActiveRecord::Base
  has_many :script_steps
  has_one :root_node, :class => 'TreeNode', :through => :root_tree_node
end

class TreeNode < ActiveRecord::Base
  belongs_to :tree
  has_one :root_tree_node
end

# This represents the join table.
class RootTreeNode < ActiveRecord::Base
  belongs_to :tree
  belongs_to :tree_node
end

What's the best way to model this relationship generally speaking, and what's the best way to set up the associations in ActiveRecord? At the end of the day, I want to be able to do something like this.

tree = Tree.create
some_node = tree.tree_nodes.create
another_node = tree.tree_nodes.create

tree.root_node = another_node
tree.save

Upvotes: 2

Views: 917

Answers (1)

Adrian Serafin
Adrian Serafin

Reputation: 7705

Hmm... If you trying to get normal tree structure like for example category tree one way to do this in rails is this:

def Category < ActiveRecord::Base
  belongs_to :parent, :class_name => "Category", :foreign_key => :parent_id
end

This means that each row has reference to its parent. Root node is the one with

parent_id == nil

Leaf node is when it's id is never used as parent_id. For more information check out acts_as_tree plugin (not sure if it works with rails 3).

Other option that you can find more usefull is nested_set (read more here)

Upvotes: 0

Related Questions