# Active Record Relations and Nesting

**URL:** <https://discuss.rubyonrails.org/t/active-record-relations-and-nesting/56409>\
**Category:** rubyonrails-talk\
**Created:** [December 23, 2010, 4:16am UTC](https://discuss.rubyonrails.org/t/active-record-relations-and-nesting/56409 "2010-12-23T04:16:32Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Devin\_M](https://avatars.discourse-cdn.com/v4/letter/d/f4b2a3/32.png) [@Devin\_M](https://discuss.rubyonrails.org/u/Devin_M)\
**Post date:** [December 23, 2010, 4:16am UTC](https://discuss.rubyonrails.org/t/active-record-relations-and-nesting/56409/1 "2010-12-23T04:16:32Z")

</div>

Hello, &nbsp;&nbsp;I am looking to create a rails app that will model and display related nodes. I am just beginning to dive into active record and I was wondering if the following pesudo code would work?

class NodeLink \< ActiveRecord::Base &nbsp;&nbsp;belongs\_to :node # foreign key - node\_id (recorded as primary\_node\_id) &nbsp;&nbsp;belongs\_to :node # foreign key - node\_id (recorded as secondary\_node\_id) end

class Node \< ActiveRecord::Base &nbsp;&nbsp;has\_many :nodes, :through =\> :node\_links end

In essence this would create something that looks like the following. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Node One] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\> \> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\> \> [Node Two] [Node Three]

> 

[Node Four]

Where the node links are represented by the lines and the nodes themselves are enclosed in brackets. And this pattern could be continued indefinite through different variations of nodes and links.

Any help or advice you could give would be great. Thanks, Devin Morin

---

<div class="post-metadata">

**Author:** ![Matt\_Jones](https://avatars.discourse-cdn.com/v4/letter/m/258eb7/32.png) [@Matt\_Jones](https://discuss.rubyonrails.org/u/Matt_Jones)\
**Post date:** [December 24, 2010, 4:13pm UTC](https://discuss.rubyonrails.org/t/active-record-relations-and-nesting/56409/2 "2010-12-24T16:13:52Z")

</div>

> Hello, I am looking to create a rails app that will model and display related nodes. I am just beginning to dive into active record and I was wondering if the following pesudo code would work?
> 
> class NodeLink \< ActiveRecord::Base belongs\_to :node # foreign key - node\_id (recorded as primary\_node\_id) belongs\_to :node # foreign key - node\_id (recorded as secondary\_node\_id) end

You'll need to specify different names for these two associations; a working declaration might look like:

class NodeLink \< ActiveRecord::Base &nbsp;&nbsp;belongs\_to :primary\_node, :class\_name =\> 'Node' &nbsp;&nbsp;belongs\_to :secondary\_node, :class\_name =\> 'Node' end

> class Node \< ActiveRecord::Base has\_many :nodes, :through =\> :node\_links end

This gets messier:

class Node \< ActiveRecord::Base &nbsp;&nbsp;has\_many :primary\_links, :foreign\_key =\> 'primary\_node\_id', :class\_name =\> 'NodeLink' &nbsp;&nbsp;has\_many :secondary\_links, :foreign\_key =\> 'secondary\_node\_id', :class\_name =\> 'NodeLink' &nbsp;&nbsp;has\_many :primary\_nodes, :through =\> :primary\_links, :source =\> :secondary\_node &nbsp;&nbsp;has\_many :secondary\_nodes, :through =\> :secondary\_links, :source =\> :primary\_node end

This offers some additional detail:

> <https://stackoverflow.com/questions/578084/how-to-implement-undirected-graph-in-ruby-on-rails>

Note that it's going to be fairly complicated to deal with "all nodes that are connected to this one" unless you denormalize somewhat and make \*two\* NodeLinks for each edge. You may want to consider if you \*really\* need a completely undirected graph, or if there's additional structure (tree-like behavior, for instance) that you can simplify things with.

If this is a central concern to your app, you may want to look into the specialized "graph databases" that are now available.

--Matt Jones

---

<div class="post-metadata">

**Author:** ![Devin\_M](https://avatars.discourse-cdn.com/v4/letter/d/f4b2a3/32.png) [@Devin\_M](https://discuss.rubyonrails.org/u/Devin_M)\
**Post date:** [December 25, 2010, 1:35am UTC](https://discuss.rubyonrails.org/t/active-record-relations-and-nesting/56409/3 "2010-12-25T01:35:09Z")

</div>

> Note that it's going to be fairly complicated to deal with "all nodes that are connected to this one" unless you denormalize somewhat and make \*two\* NodeLinks for each edge. You may want to consider if you \*really\* need a completely undirected graph, or if there's additional structure (tree-like behavior, for instance) that you can simplify things with.
> 
> If this is a central concern to your app, you may want to look into the specialized "graph databases" that are now available.
> 
> --Matt Jones

This will be a central concern of my app, is there any resources I can use to study undirected graphs? And I feel that the denormalization would be an accepted way of dealing with the issue. From what I understand this would entail having a table with

---

<div class="post-metadata">

**Author:** ![Devin\_M](https://avatars.discourse-cdn.com/v4/letter/d/f4b2a3/32.png) [@Devin\_M](https://discuss.rubyonrails.org/u/Devin_M)\
**Post date:** [December 25, 2010, 1:40am UTC](https://discuss.rubyonrails.org/t/active-record-relations-and-nesting/56409/4 "2010-12-25T01:40:04Z")

</div>

Whoops, message got cut off. From what I can guess this denormalization just basically means you store the relations between the nodes in a table to save on compute time when performing a lookup on the Db? Regards, Devin Morin

---

<div class="post-metadata">

**Author:** ![11155](https://avatars.discourse-cdn.com/v4/letter/1/d26b3c/32.png) [@11155](https://discuss.rubyonrails.org/u/11155)\
**Post date:** [December 25, 2010, 6:00pm UTC](https://discuss.rubyonrails.org/t/active-record-relations-and-nesting/56409/5 "2010-12-25T18:00:22Z")

</div>

Devin:

Unsolicited, but here's a pair of classes I've used for representing "vertices" (nodes) and "edges" (node links). You could conceptually "Vertex".gsub("NodeLink") and "Edge".gsub("Node") and get 80% of where you want to get. The useful bits:

- the belongs\_to clauses in Edge implement the kind of thing you're describing - the before\_destroy clause in Vertex takes the place of dependent =\> destroy - the edges method in Vertex finds both "left" and "right" links.

Also, this is a self-contained sample useful for testing, since it includes the up() and down() methods to create and destroy the tables while you're trying things out. I use this pattern a lot.

The example does NOT check for circular dependencies and such (since edges and vertices may describe circular graphs), but you might find it helpful.

class Edge \< ActiveRecord::Base &nbsp;&nbsp;belongs\_to :vertex\_a, :class\_name =\> 'Vertex', :foreign\_key =\> 'vertex\_a\_id' &nbsp;&nbsp;belongs\_to :vertex\_b, :class\_name =\> 'Vertex', :foreign\_key =\> 'vertex\_b\_id'

&nbsp;&nbsp;def self.up() &nbsp;&nbsp;&nbsp;&nbsp;ActiveRecord::Schema.define do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;create\_table "edges", :force =\> true do |t| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.integer "vertex\_a\_id" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.integer "vertex\_b\_id" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;end

&nbsp;&nbsp;def self.down() &nbsp;&nbsp;&nbsp;&nbsp;ActiveRecord::Schema.define do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drop\_table :edges &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;end

end

class Vertex \< ActiveRecord::Base &nbsp;&nbsp;before\_destroy do |record| &nbsp;&nbsp;&nbsp;&nbsp;Edge.destroy\_all "vertex\_a\_id = #{record.id}" &nbsp;&nbsp;&nbsp;&nbsp;Edge.destroy\_all "vertex\_b\_id = #{record.id}" &nbsp;&nbsp;end

&nbsp;&nbsp;# has\_many :vertices will not work in this case, so here's &nbsp;&nbsp;# how we find all edges asociated with this vertex... &nbsp;&nbsp;def edges &nbsp;&nbsp;&nbsp;&nbsp;Edge.find\_all\_by\_vertex\_a\_id(self.id) + Edge.find\_all\_by\_vertex\_b\_id(self.id) &nbsp;&nbsp;end

&nbsp;&nbsp;has\_many :vertices

&nbsp;&nbsp;def self.up() &nbsp;&nbsp;&nbsp;&nbsp;ActiveRecord::Schema.define do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;create\_table "vertices", :force =\> true do |t| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.float "x" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.float "y" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.float "z" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;end

&nbsp;&nbsp;def self.down() &nbsp;&nbsp;&nbsp;&nbsp;ActiveRecord::Schema.define do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drop\_table :vertices &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;end

end

# Testing...

def setup &nbsp;&nbsp;Edge.up &nbsp;&nbsp;Vertex.up &nbsp;&nbsp;v0 = Vertex.create(:x =\> 0.0, :y =\> 0.0, :z =\> 0.0) &nbsp;&nbsp;v1 = Vertex.create(:x =\> 1.0, :y =\> 1.0, :z =\> 1.0) &nbsp;&nbsp;e0 = Edge.create(:vertex\_a =\> v0, :vertex\_b =\> v1) &nbsp;&nbsp;[v0, v1, e0] end

def teardown &nbsp;&nbsp;Edge.down &nbsp;&nbsp;Vertex.down end
