namespace :nodes do
|
|
desc "Deep copy a node including descendants and attachments. Usage: rake nodes:copy[22]"
|
|
task :copy, [ :node_id ] => :environment do |t, args|
|
|
node_id = args[:node_id] || 22
|
|
begin
|
|
source = Node.find(node_id)
|
|
puts "Starting deep copy of Node #{source.id}: \"#{source.title}\"..."
|
|
|
|
# We wrap in a transaction to ensure integrity
|
|
new_root = Node.transaction do
|
|
copy_node_recursively(source)
|
|
end
|
|
|
|
puts "Successfully created deep copy!"
|
|
puts "Source ID: #{source.id}"
|
|
puts "New ID: #{new_root.id}"
|
|
rescue ActiveRecord::RecordNotFound
|
|
puts "Error: Node with ID #{node_id} not found."
|
|
rescue => e
|
|
puts "Error during copy: #{e.message}"
|
|
puts e.backtrace.first(5)
|
|
end
|
|
end
|
|
|
|
def copy_node_recursively(source, parent = nil)
|
|
# 1. Duplicate the node (this copies attributes including JSONB translations)
|
|
new_node = source.dup
|
|
|
|
# 2. Set parent (Ancestry gem handles the tree logic)
|
|
# If no parent provided, we default to the same parent as the source (sibling)
|
|
new_node.parent = parent || source.parent
|
|
|
|
# 3. Modify title of the root copy to distinguish it
|
|
if parent.nil?
|
|
I18n.available_locales.each do |locale|
|
|
title = source.title(locale: locale)
|
|
if title.present?
|
|
new_node.send(:title=, "#{title} (Copy)", locale: locale)
|
|
end
|
|
end
|
|
end
|
|
|
|
# 4. Save to get an ID
|
|
new_node.save!
|
|
|
|
# 5. Duplicate Attachments
|
|
source.attachments.each do |attachment|
|
|
new_attachment = attachment.dup
|
|
new_attachment.attachable_for = new_node
|
|
new_attachment.save!
|
|
end
|
|
|
|
# 6. Recurse for children
|
|
source.children.ordered.each do |child|
|
|
copy_node_recursively(child, new_node)
|
|
end
|
|
|
|
new_node
|
|
end
|
|
end
|