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 Hope 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,

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: http://gist.github.com/179186)

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 Erdi 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
mar...@marnen.org
--
Posted viahttp://www.ruby-forum.com/.

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

Balint

Balint Erdi 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
mar...@marnen.org
--
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,