Question

I've been hitting my head up against this one all day. Time for new eyes.

I have a tree-structured model using the ancestry gem. Works great and calling TreeNode.arrange returns a tidy little hash that is a nested tree. The problem is I'm looking for a "flattened tree" for lack of a better description. For example:

Node1
Node2
Node3
  Node4
  Node5
  Node6
    Node7
    Node8
Node9

As opposed to a more traditional

Node1
  Node2
   Node3...

So in other words I only want to "indent" my tree if there is a branch point (more than one child). I figured the best way to do this is a recursive function. I've tried several variants and I am just drawing a blank on this one :-\

def walk_until_fork(tree_hash,&blk)
   tree_hash.each do |node,children| 
    yield node.title
    if children.keys.length > 1
      #fork point
      children.each do |subnode,grandchilden|
        walk_until_fork(grandchilden,&blk)
        yield subnode.title       
      end
    else
      walk_until_fork(children,&blk)
    end
  end
end

The result of calling that test code is the fork points end up at the bottom of the output :-\

What I'd really like to see is a hash structure like that but the only keys that should have children is where a branching happened (one branch continues at that current level and each n branch after that forks).

I'm not sure if I'm being clear. I'll clarify with any questions if needed.

Was it helpful?

Solution

Deleted everything I and started over with a new approach. I'll refactor this later most likly but here was the basic idea.

def walk_until_fork(tree_hash, root_node = nil)
  root_node ||= ActiveSupport::OrderedHash.new
  tree_hash.each do |node,children|
    more_than_one = false
    parent_node = root_node[node] = ActiveSupport::OrderedHash.new
    children.each do |k,v|
      fork_node = more_than_one ? parent_node : root_node
      walk_until_fork({k => v},fork_node)
      more_than_one = true
    end
  end
  root_node
end

Then I just call with:

walk_until_fork(self.arrange)

The code passes a hash reference around to the current root, changing it to a new hash only there is more then one child.

OTHER TIPS

You can specify how many levels of nesting you want to limit it to in the CSS. To limit it to 3 levels as you're indicating you'd have the following in your CSS.

.nested_messages {
      margin-left: 30px;
    }

    .nested_messages .nested_messages .nested_messages .nested_messages{
      margin-left: 0;
    }

In this CSS above you're only able to indent 3 levels (with the associated code in your pages. After 3 levels items no longer indent. I'm just showing the CSS here, you need additional code in your views.

Ryan Bates covers this in this Railscast and has the full code example. You should be able to walk through it step by step.

http://railscasts.com/episodes/262-trees-with-ancestry

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top