From 71a95f4ca6460a7c2bc345e8b32dbef03d6dd985 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Fri, 17 Jul 2026 22:11:44 +0200 Subject: Refuse destroying nodes that still have children NestedTree's before_destroy silently delete_all'd the whole subtree, bypassing every per-node cleanup. Nodes are never destroyed recursively; descendants must be removed individually. --- app/models/node.rb | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'app/models/node.rb') diff --git a/app/models/node.rb b/app/models/node.rb index 70ed4da..6ce6591 100644 --- a/app/models/node.rb +++ b/app/models/node.rb @@ -12,9 +12,10 @@ class Node < ApplicationRecord belongs_to :lock_owner, :class_name => "User", :foreign_key => :locking_user_id, optional: true # Callbacks - after_create :initialize_empty_page - before_save :check_for_changed_slug - after_save :update_unique_names_of_children + after_create :initialize_empty_page + before_save :check_for_changed_slug + after_save :update_unique_names_of_children + before_destroy :refuse_destroy_with_children # Validations validates_length_of :slug, :within => 1..255, :unless => -> { parent_id.nil? || slug.blank? } @@ -366,6 +367,15 @@ class Node < ApplicationRecord ) end + # Nodes are never destroyed recursively + # Descendants must be removed or reparented individually first. + # The Trash feature will be the ordinary path to deletion. + def refuse_destroy_with_children + return unless children.exists? + errors.add(:base, "Cannot destroy a node that still has children") + throw :abort + end + def self.recently_changed includes(:head).where( "pages.updated_at < ? AND pages.updated_at > ? AND nodes.parent_id IS NOT NULL", -- cgit v1.3