Introduce orphan_strategy none

Many people override apply_orphan_strategy and either leave it blank or call custom methods from there.

Introducing `orphan_strategy: :none` to allows developers to skip default orphan handling.
From here a developer can add `before_destroy` with what ever logic is desired.

It is possible to introduce a custom orphan strategy with a mixin/concern,
but it doesn't seem to save any code and is not the best interface with too many nuances.
Leaving in the code for now but not promoting to a supported feature yet.
This commit is contained in:
Keenan Brock 2023-07-13 09:32:07 -04:00
parent cb9635cc3a
commit 753013a1bb
No known key found for this signature in database
GPG Key ID: DDF03448455882FC
4 changed files with 64 additions and 12 deletions

View File

@ -5,6 +5,7 @@ a nice looking [Changelog](http://keepachangelog.com).
## Version [HEAD] <sub><sup>Unreleased</sub></sup>
* Introduce `orphan_strategy: :none` [#658](https://github.com/stefankroes/ancestry/pull/658)
* Introduce `rebuild_counter_cache!` to reset counter caches. [#663](https://github.com/stefankroes/ancestry/pull/663) [#668](https://github.com/stefankroes/ancestry/pull/668) (thx @RongRongTeng)
* Documentation fixes [#664](https://github.com/stefankroes/ancestry/pull/664) [#667](https://github.com/stefankroes/ancestry/pull/667) (thx @motokikando, @onerinas)
* Introduce `build_cache_depth_sql!`, a sql alternative to `build_cache_depth` [#654](https://github.com/stefankroes/ancestry/pull/654)
@ -41,7 +42,7 @@ jobs. If you need to do this in the ui, please use `cache_depth`.
- `ancestry_primary_key_format` (introduced 4.3.0, removed by #649)
- `touch_ancestors` (introduced 2.1, removed by TODO)
* These are seen as internal and may go away:
- `apply_orphan_strategy` (TODO: use `orphan_strategy => none` and define `before_destory`)
- `apply_orphan_strategy` Please use `orphan_strategy: :none` and a custom `before_destory` instead.
## Version [4.3.3] <sub><sup>2023-04-01</sub></sup>

View File

@ -172,6 +172,7 @@ The `has_ancestry` method supports the following options:
:restrict An AncestryException is raised if any children exist
:adopt The orphan subtree is added to the parent of the deleted node
If the deleted node is Root, then rootify the orphan subtree
:none skip this logic. (add your own `before_destroy`)
:cache_depth Cache the depth of each node: (See Depth Cache section)
false Do not cache depth (default)
true Cache depth in 'ancestry_depth'

View File

@ -60,19 +60,13 @@ module Ancestry
after_update :update_descendants_with_new_ancestry, if: :ancestry_changed?
# Apply orphan strategy before destroy
case orphan_strategy
when :rootify
alias_method :apply_orphan_strategy, :apply_orphan_strategy_rootify
when :destroy
alias_method :apply_orphan_strategy, :apply_orphan_strategy_destroy
when :adopt
alias_method :apply_orphan_strategy, :apply_orphan_strategy_adopt
when :restrict
alias_method :apply_orphan_strategy, :apply_orphan_strategy_restrict
else
orphan_strategy_helper = "apply_orphan_strategy_#{orphan_strategy}"
if method_defined?(orphan_strategy_helper)
alias_method :apply_orphan_strategy, orphan_strategy_helper
before_destroy :apply_orphan_strategy
elsif orphan_strategy.to_s != "none"
raise Ancestry::AncestryException.new(I18n.t("ancestry.invalid_orphan_strategy"))
end
before_destroy :apply_orphan_strategy
# Create ancestry column accessor and set to option or default
if options[:cache_depth]

View File

@ -85,6 +85,62 @@ class OphanStrategiesTest < ActiveSupport::TestCase
end
end
def test_apply_orphan_strategy_none
AncestryTestDatabase.with_model orphan_strategy: :none do |model, roots|
root = model.create!
child = model.create!(:parent => root)
model.class_eval do
def apply_orphan_strategy
raise "this should not be called"
end
end
assert_difference 'model.count', -1 do
root.destroy
end
# this record should still exist
assert child.reload.root_id == root.id
end
end
def test_apply_orphan_strategy_custom
AncestryTestDatabase.with_model orphan_strategy: :none do |model|
model.class_eval do
before_destroy :apply_orphan_strategy_abc
def apply_orphan_strategy_abc
apply_orphan_strategy_destroy
end
end
root = model.create!
3.times { root.children.create! }
model.create! # a node that is not affected
assert_difference 'model.count', -4 do
root.destroy
end
end
end
# Not supported. Keeping around to explore for future uses.
def test_apply_orphan_strategy_custom_unsupported
AncestryTestDatabase.with_model skip_ancestry: true do |model|
model.class_eval do
# needs to be defined before calling has_ancestry
def apply_orphan_strategy_abc
apply_orphan_strategy_destroy
end
has_ancestry orphan_strategy: :abc, ancestry_column: AncestryTestDatabase.ancestry_column
end
root = model.create!
3.times { root.children.create! }
model.create! # a node that is not affected
assert_difference 'model.count', -4 do
root.destroy
end
end
end
def test_basic_delete
AncestryTestDatabase.with_model do |model|
n1 = model.create! #create a root node