Skip to content

Commit f0656ae

Browse files
authored
Merge pull request #279 from kazalt/fix-rebuild-scoping
cleanup hierarchies dependant on deleted element
2 parents 4587d8c + 78547ac commit f0656ae

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

Diff for: lib/closure_tree/hierarchy_maintenance.rb

+18-1
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,28 @@ module ClassMethods
112112
# Note that the hierarchy table will be truncated.
113113
def rebuild!
114114
_ct.with_advisory_lock do
115-
hierarchy_class.delete_all # not destroy_all -- we just want a simple truncate.
115+
cleanup!
116116
roots.find_each { |n| n.send(:rebuild!) } # roots just uses the parent_id column, so this is safe.
117117
end
118118
nil
119119
end
120+
121+
def cleanup!
122+
hierarchy_table = hierarchy_class.arel_table
123+
124+
[:descendant_id, :ancestor_id].each do |foreign_key|
125+
alias_name = foreign_key.to_s.split('_').first + "s"
126+
alias_table = Arel::Table.new(table_name).alias(alias_name)
127+
arel_join = hierarchy_table.join(alias_table, Arel::Nodes::OuterJoin)
128+
.on(alias_table[primary_key].eq(hierarchy_table[foreign_key]))
129+
.join_sources
130+
131+
lonely_childs = hierarchy_class.joins(arel_join).where(alias_table[primary_key].eq(nil))
132+
ids = lonely_childs.pluck(foreign_key)
133+
134+
hierarchy_class.where(hierarchy_table[foreign_key].in(ids)).delete_all
135+
end
136+
end
120137
end
121138
end
122139
end

Diff for: spec/db/schema.rb

-3
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,6 @@
143143
t.integer "generations", :null => false
144144
end
145145

146-
add_foreign_key(:metal_hierarchies, :metal, :column => 'ancestor_id')
147-
add_foreign_key(:metal_hierarchies, :metal, :column => 'descendant_id')
148-
149146
create_table 'menu_items' do |t|
150147
t.string 'name'
151148
t.references 'parent'

Diff for: spec/hierarchy_maintenance_spec.rb

+39
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,43 @@
1313
expect(MetalHierarchy.count).to eq(hierarchy_count)
1414
end
1515
end
16+
17+
describe '.cleanup!' do
18+
let!(:parent) { Metal.create(:value => "parent metal") }
19+
let!(:child) { Metal.create(:value => "child metal", parent: parent) }
20+
21+
before do
22+
MetalHierarchy.delete_all
23+
Metal.rebuild!
24+
end
25+
26+
context 'when an element is deleted' do
27+
it 'should delete the child hierarchies' do
28+
child.delete
29+
30+
Metal.cleanup!
31+
32+
expect(MetalHierarchy.where(descendant_id: child.id)).to be_empty
33+
expect(MetalHierarchy.where(ancestor_id: child.id)).to be_empty
34+
end
35+
36+
it 'should not delete the parent hierarchies' do
37+
child.delete
38+
Metal.cleanup!
39+
expect(MetalHierarchy.where(ancestor_id: parent.id).size).to eq 1
40+
end
41+
42+
it 'should not delete other hierarchies' do
43+
other_parent = Metal.create(:value => "other parent metal")
44+
other_child = Metal.create(:value => "other child metal", parent: other_parent)
45+
Metal.rebuild!
46+
47+
child.delete
48+
Metal.cleanup!
49+
50+
expect(MetalHierarchy.where(ancestor_id: other_parent.id).size).to eq 2
51+
expect(MetalHierarchy.where(descendant_id: other_child.id).size).to eq 2
52+
end
53+
end
54+
end
1655
end

0 commit comments

Comments
 (0)