Skip to content

Commit 0d69d67

Browse files
committed
refactor(element): Use folded_parent_element_ids for expanding nested elements
Only collect folded parent IDs when expanding an element, skipping parents that are already expanded. This avoids unnecessary updates and walks the tree with simple primary key lookups instead of loading all elements for the page version into memory. (cherry picked from commit 4129581)
1 parent c7d5717 commit 0d69d67

4 files changed

Lines changed: 42 additions & 16 deletions

File tree

app/controllers/alchemy/admin/elements_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def expand
136136
@element.update_columns(folded: false)
137137
# We want to expand the upper most parent first in order to prevent
138138
# re-painting issues in the browser
139-
parent_element_ids = @element.parent_element_ids.reverse
139+
parent_element_ids = @element.folded_parent_element_ids.reverse
140140
Alchemy::Element.where(id: parent_element_ids).update_all(folded: false)
141141

142142
render json: {

app/models/alchemy/element.rb

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,21 @@ def all_from_clipboard_for_parent_element(clipboard, parent_element)
183183
end
184184
end
185185

186-
# Heavily unoptimized naive way to get all parent ids
187-
def parent_element_ids
188-
ids ||= []
189-
parent = parent_element
190-
while parent
191-
ids.push parent.id
192-
parent = parent.parent_element
186+
# Returns IDs of all folded parent elements from immediate parent up to root
187+
#
188+
# Walks up the ancestor chain and collects only the ones that are folded,
189+
# skipping already expanded parents.
190+
#
191+
# @return [Array<Integer>] Folded parent element IDs from immediate parent to root
192+
def folded_parent_element_ids
193+
return [] unless parent_element_id
194+
195+
ids = []
196+
current_id = parent_element_id
197+
while current_id
198+
folded, parent_id = self.class.where(id: current_id).pick(:folded, :parent_element_id)
199+
ids << current_id if folded
200+
current_id = parent_id
193201
end
194202
ids
195203
end

spec/controllers/alchemy/admin/elements_controller_spec.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ module Alchemy
335335

336336
subject { post :expand, params: {id: nested_nested_folded_element.id} }
337337

338-
it "expands all parent elements" do
338+
it "expands all folded parent elements" do
339339
subject
340340
aggregate_failures do
341341
expect(nested_element.reload).to_not be_folded
@@ -345,12 +345,11 @@ module Alchemy
345345
end
346346
end
347347

348-
it "returns json" do
348+
it "returns json with only the folded parent element ids" do
349349
subject
350350
expect(JSON.parse(response.body)).to eq({
351351
"parentElementIds" => [
352352
element.id,
353-
nested_element.id,
354353
nested_nested_element.id,
355354
nested_folded_element.id
356355
],

spec/models/alchemy/element_spec.rb

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -633,15 +633,34 @@ module Alchemy
633633
end
634634
end
635635

636-
describe "#parent_element_ids" do
636+
describe "#folded_parent_element_ids" do
637637
let(:page) { create(:alchemy_page) }
638638

639-
let!(:element1) { create(:alchemy_element, page_version: page.draft_version, name: "slider", autogenerate_nested_elements: false) }
640-
let!(:element2) { create(:alchemy_element, page_version: page.draft_version, name: "slide", parent_element: element1) }
639+
let!(:element1) { create(:alchemy_element, page_version: page.draft_version, name: "slider", folded: true, autogenerate_nested_elements: false) }
640+
let!(:element2) { create(:alchemy_element, page_version: page.draft_version, name: "slide", folded: true, parent_element: element1) }
641641
let!(:element3) { create(:alchemy_element, page_version: page.draft_version, name: "slide", parent_element: element2) }
642642

643-
it "returns parent element ids" do
644-
expect(element3.parent_element_ids).to eq([element2.id, element1.id])
643+
it "returns folded parent element ids from immediate parent to root" do
644+
expect(element3.folded_parent_element_ids).to eq([element2.id, element1.id])
645+
end
646+
647+
it "returns empty array for root element" do
648+
expect(element1.folded_parent_element_ids).to eq([])
649+
end
650+
651+
it "returns single parent for first-level nested element" do
652+
expect(element2.folded_parent_element_ids).to eq([element1.id])
653+
end
654+
655+
it "skips already expanded parents" do
656+
element2.update_columns(folded: false)
657+
expect(element3.folded_parent_element_ids).to eq([element1.id])
658+
end
659+
660+
it "returns empty array when all parents are expanded" do
661+
element1.update_columns(folded: false)
662+
element2.update_columns(folded: false)
663+
expect(element3.folded_parent_element_ids).to eq([])
645664
end
646665
end
647666

0 commit comments

Comments
 (0)