feat: Add dependent: :adopt option for has_closure_tree
#471
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a new
dependent: :adoptoption tohas_closure_treethat automatically moves children to their grandparent when a parent node is destroyed. If the node being destroyed is a root (has no grandparent), children become root nodes instead.Motivation
When working with hierarchical data structures, there are scenarios where you want to remove intermediate nodes while preserving the tree structure. The existing
dependentoptions (:nullify,:destroy,:delete_all) don't provide this behavior::nullifymakes all children root nodes, which can break tree relationships:destroyand:delete_allremove the entire subtree, which may not be desiredThe
:adoptoption fills this gap by maintaining tree continuity when removing nodes, which is particularly useful for:Example Usage
Behavior
Implementation Details
Association Setup: The
has_many :childrenassociation uses:nullifywhendependent: :adoptis set (since ActiveRecord doesn't support:adoptdirectly), but the actual adoption logic is handled in thebefore_destroycallback.Adoption Logic: The
adopt_children_to_grandparentmethod:nilfor root nodes)parent_idto the grandparent IDOrder of Operations: Adoption happens before hierarchy references are deleted to ensure children can be properly identified and updated.
Backward Compatibility
This change is fully backward compatible. The new
:adoptoption is optional and doesn't affect existing behavior. All existingdependentoptions (:nullify,:destroy,:delete_all,nil) continue to work as before.