lib/nested_set/base.rb in nested_set-1.6.7 vs lib/nested_set/base.rb in nested_set-1.6.8

- old
+ new

@@ -220,11 +220,11 @@ node[left_column_name] = indices[node_scope] += 1 # find nodes_for_rebuild(node, node_scope).each{ |n| set_left_and_rights.call(n) } # set right node[right_column_name] = indices[node_scope] += 1 - node.save! + node.save(:validate => false) end # Find root node(s) root_nodes_for_rebuild.each do |root_node| node_scope = scope_for_rebuild(root_node) @@ -476,10 +476,15 @@ # Find the first sibling to the right def right_sibling siblings.where("#{q_left} > ?", left).first end + # Lock rows whose lfts and rgts are to be updated + def lock_check(cond=nil) + nested_set_scope.select(primary_key_column_name).where(cond).lock + end + # Shorthand method for finding the left sibling and moving to the left of it. def move_left move_to_left_of left_sibling end @@ -574,20 +579,23 @@ # Prunes a branch off of the tree, shifting all of the elements on the right # back to the left so the counts still work. def destroy_descendants return if right.nil? || left.nil? || skip_before_destroy - reload_nested_set - self.class.base_class.transaction do - if acts_as_nested_set_options[:dependent] == :destroy - descendants.each do |model| - model.skip_before_destroy = true - model.destroy - end - else - nested_set_scope.delete_all(["#{q_left} > ? AND #{q_right} < ?", left, right]) + lock_check(["#{quoted_right_column_name} > ?", right]) + reload_nested_set + case destroy_method + when :delete_all then + nested_set_scope.delete_all(["#{q_left} > ? AND #{q_right} < ?", left, right]) + + else + descendants.each do |model| + model.skip_before_destroy = true + model.respond_to?(destroy_method) ? model.send(destroy_method) : raise(NoMethodError, "#{model} does not have a method #{destroy_method}") + end + end # update lefts and rights for remaining nodes diff = right - left + 1 nested_set_scope.update_all( @@ -602,10 +610,15 @@ # Don't allow multiple calls to destroy to corrupt the set self.skip_before_destroy = true end end + # just a shortcut + def destroy_method + acts_as_nested_set_options[:dependent] + end + # reload left, right, and parent def reload_nested_set reload(:select => "#{quoted_left_column_name}, " + "#{quoted_right_column_name}, #{quoted_parent_column_name}") end @@ -648,14 +661,11 @@ # we have defined the boundaries of two non-overlapping intervals, # so sorting puts both the intervals and their boundaries in order a, b, c, d = [self[left_column_name], self[right_column_name], bound, other_bound].sort # select the rows in the model between a and d, and apply a lock - self.class.base_class.find(:all, - :select => primary_key_column_name, - :conditions => ["#{quoted_left_column_name} >= :a and #{quoted_right_column_name} <= :d", {:a => a, :d => d}], - :lock => true - ) + cond = ["#{quoted_left_column_name} >= :a and #{quoted_right_column_name} <= :d", { :a => a, :d => d }] + lock_check(cond) new_parent = case position when :child; target.id when :root; nil else target[parent_column_name]