From 2c0635d8b77aaad71600ef48a304197a74c08b7d Mon Sep 17 00:00:00 2001 From: Martin Meyerhoff Date: Fri, 9 Apr 2021 16:27:13 +0200 Subject: [PATCH] Delete nested elements quickly This builds an array of all the descendent elements from this element, and then calls the DeleteElements service class on them. Afterwards it resets the two associations, so that no callbacks run on in-memory deleted objects. --- app/models/alchemy/element.rb | 15 +++++++++++++++ spec/models/alchemy/element_spec.rb | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/app/models/alchemy/element.rb b/app/models/alchemy/element.rb index 26f67864bb..c828ebd9c6 100644 --- a/app/models/alchemy/element.rb +++ b/app/models/alchemy/element.rb @@ -70,6 +70,8 @@ class Element < BaseRecord has_many :contents, dependent: :destroy, inverse_of: :element + before_destroy :delete_all_nested_elements + has_many :all_nested_elements, -> { order(:position) }, class_name: "Alchemy::Element", @@ -347,5 +349,18 @@ def touch_touchable_pages touchable_pages.each(&:touch) end + + def delete_all_nested_elements + deeply_nested_elements = descendent_elements(self).flatten + DeleteElements.new(deeply_nested_elements).call + nested_elements.reset + all_nested_elements.reset + end + + def descendent_elements(element) + element.all_nested_elements + element.all_nested_elements.map do |nested_element| + descendent_elements(nested_element) + end + end end end diff --git a/spec/models/alchemy/element_spec.rb b/spec/models/alchemy/element_spec.rb index 3fa31ebcf0..d0a32ce186 100644 --- a/spec/models/alchemy/element_spec.rb +++ b/spec/models/alchemy/element_spec.rb @@ -968,4 +968,18 @@ module Alchemy end end end + + describe "destroy callbacks" do + let(:element) { create(:alchemy_element) } + let!(:nested_element_1) { create(:alchemy_element, parent_element: element) } + let!(:nested_element_2) { create(:alchemy_element, parent_element: nested_element_1) } + let!(:nested_element_3) { create(:alchemy_element, parent_element: nested_element_2) } + + it "destroys all the nested elements quickly" do + expect(Alchemy::DeleteElements).to receive(:new).with( + [nested_element_1, nested_element_2, nested_element_3] + ).and_call_original + element.reload.destroy! + end + end end