Deep nested associations on the same Model

This could be a lot simpler than I think and I’m just missing something
obvious!

I’m working on a creative collaboration app whereby one user could
submit a Story and this can then be forked by another user and worked on
seperately. To acheive this I have a has_many association within the
same Story model as such:

class Story < ActiveRecord::Base

has_many :forked_stories, :class_name => ‘Story’, :foreign_key =>
:parent_story_id

belongs_to :parent_story

end

In this way if a single story is an original it’s parent_story_id will
be nil. Similarly, if I call @story.forked_stories I can get a
collection of all the stories that have been forked from the current
one, or @story.parent_story will return the story from which it has been
forked.

What I want is to be able to return all the forked_stories and their
forked_stories for a given Story and I’m finding this very difficult
since they’re all based on the same model. I keep running into dead
ends. If I can return them to a certain depth as well that’d be great,
so I’ve been trying to write a method that accepts a depth parameter but
the crazy loops are frying my brain.

Perhaps there’s something I can do with routes that would solve the
problem?

Jon H. wrote:

This could be a lot simpler than I think and I’m just missing something
obvious!

I’m working on a creative collaboration app whereby one user could
submit a Story and this can then be forked by another user and worked on
seperately. To acheive this I have a has_many association within the
same Story model as such:

class Story < ActiveRecord::Base

has_many :forked_stories, :class_name => ‘Story’, :foreign_key =>
:parent_story_id

belongs_to :parent_story

end

In this way if a single story is an original it’s parent_story_id will
be nil. Similarly, if I call @story.forked_stories I can get a
collection of all the stories that have been forked from the current
one, or @story.parent_story will return the story from which it has been
forked.

So you have a tree structure of arbitrary depth?

What I want is to be able to return all the forked_stories and their
forked_stories for a given Story and I’m finding this very difficult
since they’re all based on the same model. I keep running into dead
ends. If I can return them to a certain depth as well that’d be great,
so I’ve been trying to write a method that accepts a depth parameter but
the crazy loops are frying my brain.

There is a less obvious but ultimately much simpler way to do this. Use
a nested-set data structure, which will make what you’re talking about
pretty easy. The awesome_nested_set plugin would be just what you need.

Perhaps there’s something I can do with routes that would solve the
problem?

No. Your issues have to do with data structure, not routing.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On Sep 1, 5:42 pm, Jon H. [email protected] wrote:

What I want is to be able to return all the forked_stories and their
forked_stories for a given Story and I’m finding this very difficult
since they’re all based on the same model. I keep running into dead
ends. If I can return them to a certain depth as well that’d be great,
so I’ve been trying to write a method that accepts a depth parameter but
the crazy loops are frying my brain.

As far as I can tell you have an algorithmical difficulty, not one
related to Rails. To get back all the forked stories for a given story
the following code snippet would do the job:

def fork_tree
forked = forked_stories
forked_from_children = forked.inject([]) do |fstories, fstory|
fstories + fstory.fork_tree
end
forked + forked_from_children
end

(you can see the whole thing here: story.rb · GitHub)

Note1: This has been tested under Ruby, not Rails
Note2: The method is badly named, since it just returns an array, not
a tree-like structure of all the stories forked directly from the
story or from its children, or grandchildren, etc.

Hope this helps,
Bálint

Balint E. wrote:

On Sep 1, 5:42�pm, Jon H. [email protected] wrote:

What I want is to be able to return all the forked_stories and their
forked_stories for a given Story and I’m finding this very difficult
since they’re all based on the same model. I keep running into dead
ends. If I can return them to a certain depth as well that’d be great,
so I’ve been trying to write a method that accepts a depth parameter but
the crazy loops are frying my brain.

As far as I can tell you have an algorithmical difficulty, not one
related to Rails. To get back all the forked stories for a given story
the following code snippet would do the job:

def fork_tree
forked = forked_stories
forked_from_children = forked.inject([]) do |fstories, fstory|
fstories + fstory.fork_tree
end
forked + forked_from_children
end

(you can see the whole thing here: story.rb · GitHub)

Note1: This has been tested under Ruby, not Rails
Note2: The method is badly named, since it just returns an array, not
a tree-like structure of all the stories forked directly from the
story or from its children, or grandchildren, etc.

Hope this helps,
B�lint

Note 3: Unless the whole array has already been loaded into memory,
that’s horribly inefficient. Nested sets are the way to go here.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Note 3: Unless the whole array has already been loaded into memory,
that’s horribly inefficient. Nested sets are the way to go here.

Best,

Marnen Laibow-Koserhttp://www.marnen.org
[email protected]

Posted viahttp://www.ruby-forum.com/.

Seems interesting, could you sketch up how that would work?

Balint

Balint E. wrote:

Note 3: Unless the whole array has already been loaded into memory,
that’s horribly inefficient. �Nested sets are the way to go here.

Best,

Marnen Laibow-Koserhttp://www.marnen.org
[email protected]

Posted viahttp://www.ruby-forum.com/.

Seems interesting, could you sketch up how that would work?

There are plenty of good articles available on nested sets (notably
those by Joe Celko and Vadim Tropashko). Check 'em out, and also look
at the awesome_nested_set rdoc!

Balint

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Best