I have a model called folder that acts as a tree. Inside the model I have an instance method copy that copies folders from one place to another. When copying a folder, its sub-folders also have to be copied.
This is my code:
class Folder < ActiveRecord::Base
acts_as_tree :order => 'name'
before_save :check_for_parent
def copy(target_folder)
new_folder = self.clone
new_folder.parent = target_folder
new_folder.save!
# Copy sub-folders recursively
self.children.each do |folder|
folder.copy(new_folder) unless folder == new_folder
end
end
def check_for_parent
raise 'Folders must have a parent.' if parent.nil? && name != 'Root folder'
end
end
Now consider the following situation:
Root folder-+
|
Folder 1-+
|
Folder 2-+
|
Folder 3
When I copy Folder 1 in the root folder it works fine. It also works when I copy Folder 1 into Folder 2, but when I copy Folder 1 into Folder 3 I end up with endless recursion. In code:
f1 = Folder.find_by_name('Folder 1')
f3 = Folder.find_by_name('Folder 3')
f1.copy(f3) # Never stops
This code leads to:
Root folder-+
|
Folder 1-+
|
Folder 2-+
|
Folder 3-+
|
Folder 1-+
|
Folder 2-+
|
Folder 3-+
|
Folder 1-+
|
Folder 2-+
|
Folder 3-+
|
Folder 1-+
|
Etc.
I am overlooking something trivial but I just can't figure it out. What am I doing wrong??
I had to keep track of which folder I originally copied. The code below works. Of course, if anyone sees room for improvement, please let me know.
def copy(target_folder, originally_copied_folder = nil)
new_folder = self.clone
new_folder.parent = target_folder
new_folder.save!
originally_copied_folder = new_folder if originally_copied_folder.nil?
# Copy sub-folders recursively
self.children.each do |folder|
folder.copy(new_folder, originally_copied_folder) unless folder == originally_copied_folder
end
end