views:

313

answers:

1

I am using "acts_as_nested_set" in my rails app. (extended with awesome nested set plugin). I was trying to logic out the best way to write a function/method to clone an element and its entire nested set so that each element gets a clone but the relationship structure mimicks the original, just with the new elements.

With nested sets you get parent_id, lft, and rgt positional columns... instead of just position_id.

Should I start at the bottom (nodes with no children) of each set and clone up through the parents all the way to a new root?

This seems like either something that has been done or that there would be a method for doing this already for nested sets but I can't see to find anything to guide me.

Thanks

A: 

I did something like this with acts-as-tree. I iterated over the collective set and cloned each item. I saved the source item and the cloned item in a hash where the source was the key and the clone the target. I then used the hash along with the parent references to resolve and remap the relations.

Here's a snippet to help convey the gist.

The clone method simply instantiates a new copy without an id. The descendants method returns a full list of descendants not just immediate ones.

def clone_branch()
  h = {self => self.clone} #we start at the root

  ordered = self.descendants #preserved order with acts_as_sortable

  #clone subitems
  ordered.each do |item|
    h[item] = item.clone
  end

  #resolve relations
  ordered.each do |item|
    cloned = h[item]
    item_parent = h[item.parent]
    item_parent.children << cloned if item_parent
  end

  h[self]
end
Mario