Skip to content

Commit

Permalink
- Version 1.1.3 (2009-11-01)
Browse files Browse the repository at this point in the history
  - Fixed a pretty bad bug where several operations took far too many queries
  • Loading branch information
stefankroes committed Nov 1, 2009
1 parent e3ea26a commit b9a102a
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 30 deletions.
4 changes: 3 additions & 1 deletion README.rdoc
Expand Up @@ -218,8 +218,10 @@ The materialised path pattern requires Ancestry to use a 'like' condition in ord

= Version history

The latest and recommended version of ancestry is 1.1.2. The three numbers of each version numbers are respectively the major, minor and patch versions. We started with major version 1 because it looks so much better and ancestry was already quite mature and complete when it was published. The major version is only bumped when backwards compatibility is broken. The minor version is bumped when new features are added. The patch version is bumped when bugs are fixed.
The latest and recommended version of ancestry is 1.1.3. The three numbers of each version numbers are respectively the major, minor and patch versions. We started with major version 1 because it looks so much better and ancestry was already quite mature and complete when it was published. The major version is only bumped when backwards compatibility is broken. The minor version is bumped when new features are added. The patch version is bumped when bugs are fixed.

- Version 1.1.3 (2009-11-01)
- Fixed a pretty bad bug where several operations took far too many queries
- Version 1.1.2 (2009-10-29)
- Added validation for depth cache column
- Added STI support (reported broken)
Expand Down
4 changes: 2 additions & 2 deletions ancestry.gemspec
Expand Up @@ -5,8 +5,8 @@ Gem::Specification.new do |s|
s.description = 'Organise ActiveRecord model into a tree structure'
s.summary = 'Ancestry allows the records of a ActiveRecord model to be organised in a tree structure, using a single, intuitively formatted database column. It exposes all the standard tree structure relations (ancestors, parent, root, children, siblings, descendants) and all of them can be fetched in a single sql query. Additional features are named_scopes, integrity checking, integrity restoration, arrangement of (sub)tree into hashes and different strategies for dealing with orphaned records.'

s.version = '1.1.2'
s.date = '2009-10-29'
s.version = '1.1.3'
s.date = '2009-11-01'

s.author = 'Stefan Kroes'
s.email = 's.a.kroes@gmail.com'
Expand Down
85 changes: 58 additions & 27 deletions lib/ancestry/acts_as_tree.rb
Expand Up @@ -168,7 +168,9 @@ def restore_ancestry_integrity!
self.base_class.all.each do |node|
# ... set its ancestry to nil if invalid
if node.errors.invalid? node.class.ancestry_column
node.update_attributes :ancestry => nil
node.without_ancestry_callbacks do
node.update_attributes :ancestry => nil
end
end
# ... save parent of this node in parents array if it exists
parents[node.id] = node.parent_id if exists? node.parent_id
Expand All @@ -187,14 +189,18 @@ def restore_ancestry_integrity!
until parent.nil?
ancestry, parent = if ancestry.nil? then parent else "#{parent}/#{ancestry}" end, parents[parent]
end
node.update_attributes node.ancestry_column => ancestry
node.without_ancestry_callbacks do
node.update_attributes node.ancestry_column => ancestry
end
end
end

# Build ancestry from parent id's for migration purposes
def build_ancestry_from_parent_ids! parent_id = nil, ancestry = nil
self.base_class.all(:conditions => {:parent_id => parent_id}).each do |node|
node.update_attribute ancestry_column, ancestry
node.without_ancestry_callbacks do
node.update_attribute ancestry_column, ancestry
end
build_ancestry_from_parent_ids! node.id, if ancestry.nil? then "#{node.id}" else "#{ancestry}/#{node.id}" end
end
end
Expand All @@ -216,37 +222,51 @@ def ancestry_exclude_self

# Update descendants with new ancestry
def update_descendants_with_new_ancestry
# If node is valid, not a new record and ancestry was updated ...
if changed.include?(self.base_class.ancestry_column.to_s) && !new_record? && valid?
# ... for each descendant ...
descendants.each do |descendant|
# ... replace old ancestry with new ancestry
descendant.update_attributes(
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
)
)
# Skip this if callbacks are disabled
unless ancestry_callbacks_disabled?
# If node is valid, not a new record and ancestry was updated ...
if changed.include?(self.base_class.ancestry_column.to_s) && !new_record? && valid?
# ... for each descendant ...
descendants.each do |descendant|
# ... replace old ancestry with new ancestry
descendant.without_ancestry_callbacks do
descendant.update_attributes(
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
)
)
end
end
end
end
end

# Apply orphan strategy
def apply_orphan_strategy
# If this isn't a new record ...
unless new_record?
# ... make al children root if orphan strategy is rootify
if self.base_class.orphan_strategy == :rootify
descendants.each do |descendant|
descendant.update_attributes descendant.class.ancestry_column => (if descendant.ancestry == child_ancestry then nil else descendant.ancestry.gsub(/^#{child_ancestry}\//, '') end)
# Skip this if callbacks are disabled
unless ancestry_callbacks_disabled?
# If this isn't a new record ...
unless new_record?
# ... make al children root if orphan strategy is rootify
if self.base_class.orphan_strategy == :rootify
descendants.each do |descendant|
descendant.without_ancestry_callbacks do
descendant.update_attributes descendant.class.ancestry_column => (if descendant.ancestry == child_ancestry then nil else descendant.ancestry.gsub(/^#{child_ancestry}\//, '') end)
end
end
# ... destroy all descendants if orphan strategy is destroy
elsif self.base_class.orphan_strategy == :destroy
descendants.all.each do |descendant|
descendant.without_ancestry_callbacks do
descendant.destroy
end
end
# ... throw an exception if it has children and orphan strategy is restrict
elsif self.base_class.orphan_strategy == :restrict
raise Ancestry::AncestryException.new('Cannot delete record because it has descendants.') unless is_childless?
end
# ... destroy all descendants if orphan strategy is destroy
elsif self.base_class.orphan_strategy == :destroy
self.base_class.destroy_all descendant_conditions
# ... throw an exception if it has children and orphan strategy is restrict
elsif self.base_class.orphan_strategy == :restrict
raise Ancestry::AncestryException.new('Cannot delete record because it has descendants.') unless is_childless?
end
end
end
Expand Down Expand Up @@ -389,6 +409,17 @@ def subtree depth_options = {}
def subtree_ids depth_options = {}
subtree(depth_options).all(:select => :id).collect(&:id)
end

# Callback disabling
def without_ancestry_callbacks
@disable_ancestry_callbacks = true
yield
@disable_ancestry_callbacks = false
end

def ancestry_callbacks_disabled?
!!@disable_ancestry_callbacks
end
end
end

Expand Down

0 comments on commit b9a102a

Please sign in to comment.