Copy node of tree with descendants
It will be also good to add besides moving nodes around to other parents the ability to copy node of tree with descendants. I wrote a temporary solution, but to my mind it's a bit hardcoded.
Migration for creation the field old_node:
class AddOldNodeToTags < ActiveRecord::Migration
def change
add_column :tags, :old_node, :integer
end
end
The model method:
def clone_descendants_to(target_node)
model = self.class
model.transaction do
self.descendants.each do |node|
parent_id = (node.parent_id == self.id) ? target_node.id : model.where(:old_node => node.parent_id).first.id
node.dup.update_attributes(:old_node => node.id, :parent_id => parent_id)
end
model.update_all({:old_node => nil}, model.arel_table[:old_node].not_eq(nil))
end
end
Usage:
Tag.first.clone_descendants_to(Tag.last)
Probably there is a more simple solution for copying subtrees to another node, and I didn't see it?
Unless I'm overlooking something simple, I believe utilizing the amoeba gem as the "guts" of your clone_descendants_to method will solve your problem without making any unneeded work for the developers of this gem.
After adding the amoeba gem to your gemfile, add the code snippet below in your Tag model (or whichever model you are using closure tree in):
amoeba do
enable
end
second, make your clone_descendants_to method look like this:
def clone_descendants_to(target_node)
# First, make sure someone didn't pass in a model
# that is not the current closure_tree model, in this case, Tag
if target_node and target_node.class.model_name.to_s == "Tag"
self_copy = self.amoeba_dup
self_copy.save
target_node.children << self_copy
else
# handle programmer error passing wrong model how ever you see fit
end
end
As you can see, those three lines of code within the if statement literally take care of everything. Not only that, but the amoeba gem lets you pass additional options during the creation of each child model, or 'node' in this case, which makes it super flexible. You can read more about the amoeba options on the amoeba github page.
Again, I have not fully tested this yet but am implementing it in my code as I type it :) ...just tested it, it looks like it worked fine. I hope my code helps you!
-Mike - mkralla11