views:

273

answers:

1

I'm using awesome_nested_set for my central website structure. I want to be able to build a UL/LI based indexbar off of the nested set but also want it to take advantage of the low database intensiveness of nested set. When I was using acts_as_tree I had a recursive function that built the indexbar. It just called itself if it encountered any children etc... I'm wondering if there's a better way to do this with nested_set. I've come up with the following so far (untested):

  def recursive_indexbar(parent, parameters)
    return unless parameters.length == 1 && parameters.first.to_i > 0

    maximum_level = parent.level + parameters.first

    content_tag :ul do
      parent.descendants.current.visible.front_end.recurse do |component_instance, block|
        content_tag :li, :class => (@item.component_instance == component_instance) ? 'uber' : false do
          component_instance.name
          unless component_instance.leaf?
            content_tag :ul, block.call
          end
        end
      end
    end
  end

Now it doesn't actually work because there is no recurse function in nested_set, I just picked that up from this link: http://dev.rubyonrails.org/ticket/9678. See the last comment on the page.

There's also going to be facility for only going so many levels deep but that's easy to implement.

Can anyone give me any pointers?

A: 

So I'll answer it then :) Basically I used a lambda and the returning function to help create a bunch of nested arrays with content. The view then decompiles this into straight text:

  def new_recursive(parent, parameters)
    return unless parameters.length == 1 && parameters.first.to_i > 0

    maximum_level = parent.level + parameters.first

    recurse = lambda do |component_instance|
      component_instance.children.current.visible.front_end.collect do |child|
        content_tag :li, :class => (@item.component_instance == child ? 'uber' : nil) do
          returning [] do |content|
            content << link_to(child.name, [child.parent, child.instance])
            unless child.leaf? || child.level == maximum_level
              content << content_tag(:ul, recurse.call(child))
            end
          end
        end
      end
    end

    content_tag :ul, recurse.call(parent)
  end

Note also the use of collect rather than each (which would seem more logical). Collect returns an array which is what we want. If stop appending or nesting within the original array the whole thing breaks down :)

Hope this helps someone in the future. It's a but customised to my uses but will transfer to any tree structure. I guess getting it to work with nested set efficiently would be cool but since an index bar is usually only one or two levels deep the recursiveness won't get out of control.

Brendon Muir