From e2f88c1c6a38619d49a841ae561222d4d62a8f49 Mon Sep 17 00:00:00 2001 From: Micah Geisel Date: Thu, 7 Mar 2024 19:22:51 -0600 Subject: [PATCH] Teach `#move_to_child_with_index` to accept `:root` as a target (#481) * teach #move_to_child_with_index to accept :root as a target. * refactor out duplication within #move_to_child_with_index. * teach #move_to_child_of to also accept :root and use it internally within #move_to_child_with_index. * extract #roots which is a instance-level version of .roots, and use within #move_to_child_with_index. * update CHANGELOG. --------- Co-authored-by: Micah Geisel --- CHANGELOG | 2 ++ lib/awesome_nested_set/model/movable.rb | 19 ++++++++++++------- lib/awesome_nested_set/model/relatable.rb | 4 ++++ spec/awesome_nested_set_spec.rb | 21 +++++++++++++++++++++ 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f04d6741..6a50a111 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,6 @@ Unreleased version +* Teach #move_to_child_of and #move_to_child_with_index to accept :root as a parameter [Micah Geisel](https://github.com/botandrose) +* Add #roots method [Micah Geisel](https://github.com/botandrose) 3.6.0 * Support Rails 7.1 [Harshal Bhakta](https://github.com/harshalbhakta) diff --git a/lib/awesome_nested_set/model/movable.rb b/lib/awesome_nested_set/model/movable.rb index 4b1bacf9..6d1e26d0 100644 --- a/lib/awesome_nested_set/model/movable.rb +++ b/lib/awesome_nested_set/model/movable.rb @@ -36,26 +36,31 @@ def move_to_right_of(node) # Move the node to the child of another node def move_to_child_of(node) - move_to node, :child + if node == :root + move_to_root + else + move_to node, :child + end end # Move the node to the child of another node with specify index def move_to_child_with_index(node, index) - if node.children.empty? + siblings = node == :root ? roots : node.children + if siblings.empty? move_to_child_of(node) - elsif node.children.count == index - move_to_right_of(node.children.last) + elsif siblings.count == index + move_to_right_of(siblings.last) else - my_position = node.children.to_a.index(self) + my_position = siblings.index(self) if my_position && my_position < index # e.g. if self is at position 0 and we want to move self to position 1 then self # needs to move to the *right* of the node at position 1. That's because the node # that is currently at position 1 will be at position 0 after the move completes. - move_to_right_of(node.children[index]) + move_to_right_of(siblings[index]) elsif my_position && my_position == index # do nothing. already there. else - move_to_left_of(node.children[index]) + move_to_left_of(siblings[index]) end end end diff --git a/lib/awesome_nested_set/model/relatable.rb b/lib/awesome_nested_set/model/relatable.rb index f81aaaf6..d8fdddc8 100644 --- a/lib/awesome_nested_set/model/relatable.rb +++ b/lib/awesome_nested_set/model/relatable.rb @@ -93,6 +93,10 @@ def root end end + def roots + nested_set_scope.where(parent_id: nil) + end + protected def compute_level diff --git a/spec/awesome_nested_set_spec.rb b/spec/awesome_nested_set_spec.rb index 970e861d..18059fa6 100644 --- a/spec/awesome_nested_set_spec.rb +++ b/spec/awesome_nested_set_spec.rb @@ -136,6 +136,10 @@ end end + it "roots" do + expect(categories(:child_3).roots).to eq([categories(:top_level), categories(:top_level_2)]) + end + it "root_class_method" do expect(Category.root).to eq(categories(:top_level)) end @@ -510,6 +514,16 @@ expect(Category.valid?).to be_truthy end + it "move_to_child_of :root" do + categories(:child_2).move_to_child_of(:root) + expect(categories(:child_2).parent).to be_nil + expect(categories(:child_2).level).to eq(0) + expect(categories(:child_2_1).level).to eq(1) + expect(categories(:child_2).left).to eq(9) + expect(categories(:child_2).right).to eq(12) + expect(Category.valid?).to be_truthy + end + describe "#move_to_child_with_index" do it "move to a node without child" do categories(:child_1).move_to_child_with_index(categories(:child_3), 0) @@ -562,6 +576,13 @@ expect(categories(:child_1).left).to eq(2) expect(categories(:child_1).right).to eq(3) end + + it "move to top level with specified index" do + categories(:child_1).move_to_child_with_index(:root, 1) + expect(categories(:child_1).parent_id).to be_nil + expect(categories(:child_1).left).to eq(9) + expect(categories(:child_1).right).to eq(10) + end end it "move_to_child_of_appends_to_end" do