Correctly set the ancestry column when creating a child within an after_* callback #57

Closed
wants to merge 2 commits into from
View
19 lib/ancestry/instance_methods.rb
@@ -18,8 +18,8 @@ def update_descendants_with_new_ancestry
descendant.update_attribute(
self.base_class.ancestry_column,
descendant.read_attribute(descendant.class.ancestry_column).gsub(
- /^#{self.child_ancestry}/,
- if read_attribute(self.class.ancestry_column).blank? then id.to_s else "#{read_attribute self.class.ancestry_column }/#{id}" end
+ /^#{self.child_ancestry_was}/,
+ self.child_ancestry
)
)
end
@@ -61,7 +61,16 @@ 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?
- if self.send("#{self.base_class.ancestry_column}_was").blank? then id.to_s else "#{self.send "#{self.base_class.ancestry_column}_was"}/#{id}" end
+ ancestry = self.send(self.ancestry_column)
+ if ancestry.blank? then self.id.to_s else ancestry.to_s + "/#{self.id.to_s}" end
+ end
+
+ def child_ancestry_was
+ # New records cannot have children
+ raise Ancestry::AncestryException.new('No child ancestry for new record. Save record before performing tree operations.') if new_record?
+
+ ancestry = self.send("#{self.ancestry_column}_was")
+ if ancestry.blank? then self.id.to_s else ancestry.to_s + "/#{self.id.to_s}" end
end
# Ancestors
@@ -171,7 +180,7 @@ def is_only_child?
# Descendants
def descendant_conditions
- ["#{self.base_class.table_name}.#{self.base_class.ancestry_column} like ? or #{self.base_class.table_name}.#{self.base_class.ancestry_column} = ?", "#{child_ancestry}/%", child_ancestry]
+ ["#{self.base_class.table_name}.#{self.base_class.ancestry_column} like ? or #{self.base_class.table_name}.#{self.base_class.ancestry_column} = ?", "#{child_ancestry_was}/%", child_ancestry_was]
end
def descendants depth_options = {}
@@ -184,7 +193,7 @@ def descendant_ids depth_options = {}
# Subtree
def subtree_conditions
- ["#{self.base_class.table_name}.#{self.base_class.primary_key} = ? or #{self.base_class.table_name}.#{self.base_class.ancestry_column} like ? or #{self.base_class.table_name}.#{self.base_class.ancestry_column} = ?", self.id, "#{child_ancestry}/%", child_ancestry]
+ ["#{self.base_class.table_name}.#{self.base_class.primary_key} = ? or #{self.base_class.table_name}.#{self.base_class.ancestry_column} like ? or #{self.base_class.table_name}.#{self.base_class.ancestry_column} = ?", self.id, "#{child_ancestry_was}/%", child_ancestry_was]
end
def subtree depth_options = {}
View
16 test/has_ancestry_test.rb
@@ -448,6 +448,22 @@ def test_node_creation_though_scope
end
end
+ def test_node_creation_in_after_create
+ AncestryTestDatabase.with_model do |model|
+ children=[]
+ model.instance_eval do
+ attr_accessor :idx
+ self.after_create do
+ children << self.children.create!(:idx => self.idx - 1) if self.idx > 0
+ end
+ end
+ node = model.create!(:idx => 3)
+ # In the error case, the ancestry on each item will only contain the parent's id,
+ # and not the entire ancestry tree.
+ assert_equal '1/2/3', children.first.ancestry
+ end
+ end
+
def test_validate_ancestry_exclude_self
AncestryTestDatabase.with_model do |model|
parent = model.create!