From afb269db24ede13f93531168d3136afa6e1b18db Mon Sep 17 00:00:00 2001 From: Tim Kretschmer Date: Wed, 27 Jan 2021 12:17:12 +0100 Subject: [PATCH] add :child_order to .rebuild! in order to respect a certain children order when calling rebuild! the children will be reordered with whatever the argument of `child_order` was --- README.md | 2 ++ lib/closure_tree/hierarchy_maintenance.rb | 8 ++++---- spec/closure_tree/hierarchy_maintenance_spec.rb | 9 +++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5250bdc9..c1567973 100644 --- a/README.md +++ b/README.md @@ -404,6 +404,8 @@ end ``` This way, the complete hierarchy including all subclasses will be rebuilt. +If you need to preserve a certain children order to rebuild your tree you can call `rebuild` with the keyword `child_order` and give a regular ordering hash: `rebuild!(child_order: {name: :desc})` + ## Deterministic ordering By default, children will be ordered by your database engine, which may not be what you want. diff --git a/lib/closure_tree/hierarchy_maintenance.rb b/lib/closure_tree/hierarchy_maintenance.rb index 3023b247..acc56714 100644 --- a/lib/closure_tree/hierarchy_maintenance.rb +++ b/lib/closure_tree/hierarchy_maintenance.rb @@ -62,7 +62,7 @@ def _ct_before_destroy true # don't prevent destruction end - def rebuild!(called_by_rebuild = false) + def rebuild!(called_by_rebuild = false, child_order: nil) _ct.with_advisory_lock do delete_hierarchy_references unless (defined? @was_new_record) && @was_new_record hierarchy_class.create!(:ancestor => self, :descendant => self, :generations => 0) @@ -82,7 +82,7 @@ def rebuild!(called_by_rebuild = false) _ct_reorder_siblings if !called_by_rebuild end - children.find_each { |c| c.rebuild!(true) } + children.reorder(child_order).find_each { |c| c.rebuild!(true, child_order: child_order) } _ct_reorder_children if _ct.order_is_numeric? && children.present? end @@ -110,10 +110,10 @@ def delete_hierarchy_references module ClassMethods # Rebuilds the hierarchy table based on the parent_id column in the database. # Note that the hierarchy table will be truncated. - def rebuild! + def rebuild!(child_order: nil) _ct.with_advisory_lock do cleanup! - roots.find_each { |n| n.send(:rebuild!) } # roots just uses the parent_id column, so this is safe. + roots.find_each { |n| n.send(:rebuild!, child_order: child_order) } # roots just uses the parent_id column, so this is safe. end nil end diff --git a/spec/closure_tree/hierarchy_maintenance_spec.rb b/spec/closure_tree/hierarchy_maintenance_spec.rb index a4ad09f5..321391b4 100644 --- a/spec/closure_tree/hierarchy_maintenance_spec.rb +++ b/spec/closure_tree/hierarchy_maintenance_spec.rb @@ -12,6 +12,15 @@ Metal.rebuild! expect(MetalHierarchy.count).to eq(hierarchy_count) end + + it 'rebuild tree with specific child order' do + parent = Metal.create(value: "Parent") + Metal.create(value: "name3") + Metal.create(value: "name1") + Metal.create(value: "name2") + expect(parent.children).to receive(:reorder).with({value: :desc}).once.and_call_original + parent.rebuild!(child_order: {value: :desc}) + end end describe '.cleanup!' do