update_descendants_with_new_ancestry in after_update
This commit is contained in:
parent
aabf5d2112
commit
0fcd12fd36
|
|
@ -45,8 +45,8 @@ module Ancestry
|
|||
# Validate that the ancestor ids don't include own id
|
||||
validate :ancestry_exclude_self
|
||||
|
||||
# Update descendants with new ancestry before save
|
||||
before_save :update_descendants_with_new_ancestry
|
||||
# Update descendants with new ancestry after update
|
||||
after_update :update_descendants_with_new_ancestry
|
||||
|
||||
# Apply orphan strategy before destroy
|
||||
before_destroy :apply_orphan_strategy
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@ module Ancestry
|
|||
errors.add(:base, I18n.t("ancestry.exclude_self", class_name: self.class.name.humanize)) if ancestor_ids.include? self.id
|
||||
end
|
||||
|
||||
# Update descendants with new ancestry (before save)
|
||||
# Update descendants with new ancestry (after update)
|
||||
def update_descendants_with_new_ancestry
|
||||
# If enabled and node is existing and ancestry was updated and the new ancestry is sane ...
|
||||
if !ancestry_callbacks_disabled? && !new_record? && ancestry_changed? && sane_ancestor_ids?
|
||||
# ... for each descendant ...
|
||||
unscoped_descendants.each do |descendant|
|
||||
unscoped_descendants_before_save.each do |descendant|
|
||||
# ... replace old ancestry with new ancestry
|
||||
descendant.without_ancestry_callbacks do
|
||||
new_ancestor_ids = path_ids + (descendant.ancestor_ids - path_ids_in_database)
|
||||
new_ancestor_ids = path_ids + (descendant.ancestor_ids - path_ids_before_last_save)
|
||||
descendant.update_attribute(:ancestor_ids, new_ancestor_ids)
|
||||
end
|
||||
end
|
||||
|
|
@ -133,8 +133,8 @@ module Ancestry
|
|||
ancestor_ids + [id]
|
||||
end
|
||||
|
||||
def path_ids_in_database
|
||||
ancestor_ids_in_database + [id]
|
||||
def path_ids_before_last_save
|
||||
ancestor_ids_before_last_save + [id]
|
||||
end
|
||||
|
||||
def path depth_options = {}
|
||||
|
|
@ -312,6 +312,12 @@ module Ancestry
|
|||
end
|
||||
end
|
||||
|
||||
def unscoped_descendants_before_save
|
||||
unscoped_where do |scope|
|
||||
scope.where self.ancestry_base_class.descendant_before_save_conditions(self)
|
||||
end
|
||||
end
|
||||
|
||||
# works with after save context (hence before_last_save)
|
||||
def unscoped_current_and_previous_ancestors
|
||||
unscoped_where do |scope|
|
||||
|
|
|
|||
|
|
@ -50,11 +50,19 @@ module Ancestry
|
|||
indirects_of(node).or(children_of(node))
|
||||
end
|
||||
|
||||
# deprecated
|
||||
def descendant_conditions(object)
|
||||
def descendants_by_ancestry(ancestry)
|
||||
t = arel_table
|
||||
t[ancestry_column].matches("#{ancestry}/%", nil, true).or(t[ancestry_column].eq(ancestry))
|
||||
end
|
||||
|
||||
def descendant_conditions(object)
|
||||
node = to_node(object)
|
||||
t[ancestry_column].matches("#{node.child_ancestry}/%", nil, true).or(t[ancestry_column].eq(node.child_ancestry))
|
||||
descendants_by_ancestry( node.child_ancestry )
|
||||
end
|
||||
|
||||
def descendant_before_save_conditions(object)
|
||||
node = to_node(object)
|
||||
descendants_by_ancestry( node.child_ancestry_before_save )
|
||||
end
|
||||
|
||||
def subtree_of(object)
|
||||
|
|
@ -102,10 +110,6 @@ module Ancestry
|
|||
parse_ancestry_column(read_attribute(self.ancestry_base_class.ancestry_column))
|
||||
end
|
||||
|
||||
def ancestor_ids_in_database
|
||||
parse_ancestry_column(send("#{self.ancestry_base_class.ancestry_column}#{IN_DATABASE_SUFFIX}"))
|
||||
end
|
||||
|
||||
def ancestor_ids_before_last_save
|
||||
parse_ancestry_column(send("#{self.ancestry_base_class.ancestry_column}#{BEFORE_LAST_SAVE_SUFFIX}"))
|
||||
end
|
||||
|
|
@ -132,6 +136,13 @@ module Ancestry
|
|||
path_was.blank? ? id.to_s : "#{path_was}#{ANCESTRY_DELIMITER}#{id}"
|
||||
end
|
||||
|
||||
def child_ancestry_before_save
|
||||
# New records cannot have children
|
||||
raise Ancestry::AncestryException.new(I18n.t("ancestry.no_child_for_new_record")) if new_record?
|
||||
path_was = self.send("#{self.ancestry_base_class.ancestry_column}#{BEFORE_LAST_SAVE_SUFFIX}")
|
||||
path_was.blank? ? id.to_s : "#{path_was}#{ANCESTRY_DELIMITER}#{id}"
|
||||
end
|
||||
|
||||
def parse_ancestry_column(obj)
|
||||
return [] if obj == ROOT
|
||||
obj_ids = obj.split(ANCESTRY_DELIMITER)
|
||||
|
|
|
|||
|
|
@ -25,21 +25,25 @@ module Ancestry
|
|||
reorder(Arel::Nodes::Ascending.new(arel_table[ancestry_column]), order)
|
||||
end
|
||||
|
||||
# deprecated
|
||||
def descendant_conditions(object)
|
||||
t = arel_table
|
||||
node = to_node(object)
|
||||
t[ancestry_column].matches("#{node.child_ancestry}%", nil, true)
|
||||
def descendants_by_ancestry(ancestry)
|
||||
arel_table[ancestry_column].matches("#{ancestry}/%", nil, true)
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def child_ancestry
|
||||
# New records cannot have children
|
||||
raise Ancestry::AncestryException.new('No child ancestry for new record. Save record before performing tree operations.') if new_record?
|
||||
raise Ancestry::AncestryException.new(I18n.t("ancestry.no_child_for_new_record")) if new_record?
|
||||
path_was = self.send("#{self.ancestry_base_class.ancestry_column}#{IN_DATABASE_SUFFIX}")
|
||||
"#{path_was}#{id}#{ANCESTRY_DELIMITER}"
|
||||
end
|
||||
|
||||
def child_ancestry_before_save
|
||||
# New records cannot have children
|
||||
raise Ancestry::AncestryException.new(I18n.t("ancestry.no_child_for_new_record")) if new_record?
|
||||
path_was = self.send("#{self.ancestry_base_class.ancestry_column}#{BEFORE_LAST_SAVE_SUFFIX}")
|
||||
"#{path_was}#{id}#{ANCESTRY_DELIMITER}"
|
||||
end
|
||||
|
||||
def parse_ancestry_column(obj)
|
||||
return [] if obj == ROOT
|
||||
obj_ids = obj.split(ANCESTRY_DELIMITER).delete_if(&:blank?)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
module Ancestry
|
||||
module MaterializedPathPg
|
||||
# Update descendants with new ancestry (before save)
|
||||
# Update descendants with new ancestry (after update)
|
||||
def update_descendants_with_new_ancestry
|
||||
# If enabled and node is existing and ancestry was updated and the new ancestry is sane ...
|
||||
if !ancestry_callbacks_disabled? && !new_record? && ancestry_changed? && sane_ancestor_ids?
|
||||
ancestry_column = ancestry_base_class.ancestry_column
|
||||
old_ancestry = path_ids_in_database.join(Ancestry::MaterializedPath::ANCESTRY_DELIMITER)
|
||||
old_ancestry = path_ids_before_last_save.join(Ancestry::MaterializedPath::ANCESTRY_DELIMITER)
|
||||
new_ancestry = path_ids.join(Ancestry::MaterializedPath::ANCESTRY_DELIMITER)
|
||||
update_clause = [
|
||||
"#{ancestry_column} = regexp_replace(#{ancestry_column}, '^#{old_ancestry}', '#{new_ancestry}')"
|
||||
|
|
@ -16,7 +16,7 @@ module Ancestry
|
|||
update_clause << "#{depth_cache_column} = length(regexp_replace(regexp_replace(ancestry, '^#{old_ancestry}', '#{new_ancestry}'), '\\d', '', 'g')) + 1"
|
||||
end
|
||||
|
||||
unscoped_descendants.update_all update_clause.join(', ')
|
||||
unscoped_descendants_before_save.update_all update_clause.join(', ')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue