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