diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-17 22:11:44 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-17 22:11:44 +0200 |
| commit | 71a95f4ca6460a7c2bc345e8b32dbef03d6dd985 (patch) | |
| tree | 48ba0ccdc1941343bdb2632ec5724ce38fd9ecfb /app/models/node.rb | |
| parent | e3021c88a0ce35b4c069e148a5d82bb1acbd3c91 (diff) | |
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.
Diffstat (limited to 'app/models/node.rb')
| -rw-r--r-- | app/models/node.rb | 16 |
1 files changed, 13 insertions, 3 deletions
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 | |||
| 12 | belongs_to :lock_owner, :class_name => "User", :foreign_key => :locking_user_id, optional: true | 12 | belongs_to :lock_owner, :class_name => "User", :foreign_key => :locking_user_id, optional: true |
| 13 | 13 | ||
| 14 | # Callbacks | 14 | # Callbacks |
| 15 | after_create :initialize_empty_page | 15 | after_create :initialize_empty_page |
| 16 | before_save :check_for_changed_slug | 16 | before_save :check_for_changed_slug |
| 17 | after_save :update_unique_names_of_children | 17 | after_save :update_unique_names_of_children |
| 18 | before_destroy :refuse_destroy_with_children | ||
| 18 | 19 | ||
| 19 | # Validations | 20 | # Validations |
| 20 | validates_length_of :slug, :within => 1..255, :unless => -> { parent_id.nil? || slug.blank? } | 21 | validates_length_of :slug, :within => 1..255, :unless => -> { parent_id.nil? || slug.blank? } |
| @@ -366,6 +367,15 @@ class Node < ApplicationRecord | |||
| 366 | ) | 367 | ) |
| 367 | end | 368 | end |
| 368 | 369 | ||
| 370 | # Nodes are never destroyed recursively | ||
| 371 | # Descendants must be removed or reparented individually first. | ||
| 372 | # The Trash feature will be the ordinary path to deletion. | ||
| 373 | def refuse_destroy_with_children | ||
| 374 | return unless children.exists? | ||
| 375 | errors.add(:base, "Cannot destroy a node that still has children") | ||
| 376 | throw :abort | ||
| 377 | end | ||
| 378 | |||
| 369 | def self.recently_changed | 379 | def self.recently_changed |
| 370 | includes(:head).where( | 380 | includes(:head).where( |
| 371 | "pages.updated_at < ? AND pages.updated_at > ? AND nodes.parent_id IS NOT NULL", | 381 | "pages.updated_at < ? AND pages.updated_at > ? AND nodes.parent_id IS NOT NULL", |
