Skip to content

cleanup hierarchies dependant on deleted element #279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion lib/closure_tree/hierarchy_maintenance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 0 additions & 3 deletions spec/db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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.integer 'parent_id'
Expand Down
39 changes: 39 additions & 0 deletions spec/hierarchy_maintenance_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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