diff --git a/CHANGELOG.md b/CHANGELOG.md
index 05f2227..e3ee213 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@ a nice looking [Changelog](http://keepachangelog.com).
## Version [HEAD] Unreleased
+* 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] 2023-04-01
diff --git a/README.md b/README.md
index 71deede..37567c6 100644
--- a/README.md
+++ b/README.md
@@ -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'
diff --git a/lib/ancestry/has_ancestry.rb b/lib/ancestry/has_ancestry.rb
index f3773c4..55daed9 100644
--- a/lib/ancestry/has_ancestry.rb
+++ b/lib/ancestry/has_ancestry.rb
@@ -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]
diff --git a/test/concerns/orphan_strategies_test.rb b/test/concerns/orphan_strategies_test.rb
index 8474a73..bb4d12c 100644
--- a/test/concerns/orphan_strategies_test.rb
+++ b/test/concerns/orphan_strategies_test.rb
@@ -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