Permalink
Browse files

Merge pull request #279 from kazalt/fix-rebuild-scoping

cleanup hierarchies dependant on deleted element
  • Loading branch information...
mceachen committed Oct 2, 2018
2 parents 4587d8c + 78547ac commit f0656aefc38fbe47349bf56319ccf2c94ae85e67
Showing with 57 additions and 4 deletions.
  1. +18 −1 lib/closure_tree/hierarchy_maintenance.rb
  2. +0 −3 spec/db/schema.rb
  3. +39 −0 spec/hierarchy_maintenance_spec.rb
@@ -112,11 +112,28 @@ module ClassMethods
# Note that the hierarchy table will be truncated.
def rebuild!
_ct.with_advisory_lock do
hierarchy_class.delete_all # not destroy_all -- we just want a simple truncate.
cleanup!
roots.find_each { |n| n.send(:rebuild!) } # roots just uses the parent_id column, so this is safe.
end
nil
end

def cleanup!
hierarchy_table = hierarchy_class.arel_table

[:descendant_id, :ancestor_id].each do |foreign_key|
alias_name = foreign_key.to_s.split('_').first + "s"
alias_table = Arel::Table.new(table_name).alias(alias_name)
arel_join = hierarchy_table.join(alias_table, Arel::Nodes::OuterJoin)
.on(alias_table[primary_key].eq(hierarchy_table[foreign_key]))
.join_sources

lonely_childs = hierarchy_class.joins(arel_join).where(alias_table[primary_key].eq(nil))
ids = lonely_childs.pluck(foreign_key)

hierarchy_class.where(hierarchy_table[foreign_key].in(ids)).delete_all
end
end
end
end
end
@@ -143,9 +143,6 @@
t.integer "generations", :null => false
end

add_foreign_key(:metal_hierarchies, :metal, :column => 'ancestor_id')
add_foreign_key(:metal_hierarchies, :metal, :column => 'descendant_id')

create_table 'menu_items' do |t|
t.string 'name'
t.references 'parent'
@@ -13,4 +13,43 @@
expect(MetalHierarchy.count).to eq(hierarchy_count)
end
end

describe '.cleanup!' do
let!(:parent) { Metal.create(:value => "parent metal") }
let!(:child) { Metal.create(:value => "child metal", parent: parent) }

before do
MetalHierarchy.delete_all
Metal.rebuild!
end

context 'when an element is deleted' do
it 'should delete the child hierarchies' do
child.delete

Metal.cleanup!

expect(MetalHierarchy.where(descendant_id: child.id)).to be_empty
expect(MetalHierarchy.where(ancestor_id: child.id)).to be_empty
end

it 'should not delete the parent hierarchies' do
child.delete
Metal.cleanup!
expect(MetalHierarchy.where(ancestor_id: parent.id).size).to eq 1
end

it 'should not delete other hierarchies' do
other_parent = Metal.create(:value => "other parent metal")
other_child = Metal.create(:value => "other child metal", parent: other_parent)
Metal.rebuild!

child.delete
Metal.cleanup!

expect(MetalHierarchy.where(ancestor_id: other_parent.id).size).to eq 2
expect(MetalHierarchy.where(descendant_id: other_child.id).size).to eq 2
end
end
end
end

0 comments on commit f0656ae

Please sign in to comment.