|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +require 'test_helper' |
| 4 | + |
| 5 | +class RebuildWithCallbacksTest < ActiveSupport::TestCase |
| 6 | + # Test for issue #392 comment 3568009891 |
| 7 | + # User 'bb' reported MissingAttributeError during rebuild! after fix |
| 8 | + # The hierarchy class inherits from abstract base and should not trigger |
| 9 | + # parent model callbacks during hierarchy rebuild operations |
| 10 | + |
| 11 | + def setup |
| 12 | + Tag.delete_all |
| 13 | + TagHierarchy.delete_all |
| 14 | + end |
| 15 | + |
| 16 | + test 'Tag.rebuild! does not trigger before_destroy callbacks on hierarchy records' do |
| 17 | + # Tag has before_destroy :add_destroyed_tag callback |
| 18 | + # TagHierarchy should NOT inherit this callback |
| 19 | + |
| 20 | + root = Tag.create!(name: 'root') |
| 21 | + _child = Tag.create!(name: 'child', parent: root) |
| 22 | + |
| 23 | + initial_hierarchy_count = TagHierarchy.count |
| 24 | + assert initial_hierarchy_count > 0, "Should have hierarchy records" |
| 25 | + |
| 26 | + initial_destroyed_count = DestroyedTag.count |
| 27 | + |
| 28 | + # This should rebuild hierarchy without triggering Tag callbacks |
| 29 | + assert_nothing_raised do |
| 30 | + Tag.rebuild! |
| 31 | + end |
| 32 | + |
| 33 | + # Hierarchy records should be recreated |
| 34 | + assert_equal initial_hierarchy_count, TagHierarchy.count |
| 35 | + |
| 36 | + # DestroyedTag should NOT increase (proves callbacks weren't triggered) |
| 37 | + assert_equal initial_destroyed_count, DestroyedTag.count, |
| 38 | + "TagHierarchy operations should not trigger Tag's before_destroy callback" |
| 39 | + end |
| 40 | + |
| 41 | + test 'TagHierarchy.create does not inherit Tag validations or callbacks' do |
| 42 | + # Direct hierarchy insertion should work without triggering parent callbacks |
| 43 | + _root = Tag.create!(name: 'root') |
| 44 | + _child = Tag.create!(name: 'child', parent: _root) |
| 45 | + |
| 46 | + destroyed_count_before = DestroyedTag.count |
| 47 | + |
| 48 | + # TagHierarchy.create! should not trigger Tag's before_destroy callback |
| 49 | + # This verifies TagHierarchy doesn't inherit Tag's callbacks |
| 50 | + # Note: In normal operation, has_closure_tree automatically creates hierarchy records |
| 51 | + # This test verifies manual creation doesn't trigger Tag callbacks |
| 52 | + |
| 53 | + initial_hierarchy_count = TagHierarchy.count |
| 54 | + |
| 55 | + # Verify the hierarchy class doesn't inherit Tag's callback behavior |
| 56 | + tag_destroy_callbacks = Tag._destroy_callbacks.to_a |
| 57 | + hierarchy_destroy_callbacks = TagHierarchy._destroy_callbacks.to_a |
| 58 | + |
| 59 | + assert_not_equal tag_destroy_callbacks.length, hierarchy_destroy_callbacks.length, |
| 60 | + "TagHierarchy should not inherit all of Tag's callbacks" |
| 61 | + |
| 62 | + # Hierarchy operations should not trigger the before_destroy callback |
| 63 | + assert_equal destroyed_count_before, DestroyedTag.count, |
| 64 | + "TagHierarchy class definition should not trigger Tag's callbacks" |
| 65 | + |
| 66 | + assert initial_hierarchy_count > 0, "Should have hierarchy records from Tag creation" |
| 67 | + end |
| 68 | + |
| 69 | + test 'TagHierarchy inherits from ApplicationRecord not Tag' do |
| 70 | + # Force TagHierarchy to be loaded |
| 71 | + Tag._ct |
| 72 | + |
| 73 | + # TagHierarchy should inherit from ApplicationRecord (abstract base) |
| 74 | + # NOT from Tag (which has callbacks/validations) |
| 75 | + assert_equal ApplicationRecord, TagHierarchy.superclass, |
| 76 | + "TagHierarchy should inherit from ApplicationRecord, not Tag" |
| 77 | + |
| 78 | + # Verify it doesn't inherit Tag's callbacks |
| 79 | + _tag_callbacks = Tag._destroy_callbacks.map(&:filter) |
| 80 | + hierarchy_callbacks = TagHierarchy._destroy_callbacks.map(&:filter) |
| 81 | + |
| 82 | + assert_not_includes hierarchy_callbacks, :add_destroyed_tag, |
| 83 | + "TagHierarchy should not inherit add_destroyed_tag callback from Tag" |
| 84 | + end |
| 85 | + |
| 86 | + test 'TagHierarchy has correct primary key set' do |
| 87 | + # Issue #392 comment showed RETURNING clause issues |
| 88 | + # Verify composite primary key is correctly set |
| 89 | + |
| 90 | + assert_equal %w[ancestor_id descendant_id generations], TagHierarchy.primary_key, |
| 91 | + "TagHierarchy should use composite primary key" |
| 92 | + end |
| 93 | +end |
0 commit comments