module CollectiveIdea::Acts::NestedSet::Model

Public Instance Methods

child?() click to toggle source

Returns true is this is a child node

# File lib/awesome_nested_set/model.rb, line 129
def child?
  !root?
end
leaf?() click to toggle source

Returns true if this is the end of a branch.

# File lib/awesome_nested_set/model.rb, line 134
def leaf?
  persisted? && right.to_i - left.to_i == 1
end
left(target = self) click to toggle source

Value of the left column

# File lib/awesome_nested_set/model.rb, line 114
def left(target = self)
  target[left_column_name]
end
nested_set_scope(options = {}) click to toggle source

All nested set queries should use this #nested_set_scope, which performs finds on the base ActiveRecord class, using the :scope declared in the acts_as_nested_set declaration.

# File lib/awesome_nested_set/model.rb, line 141
def nested_set_scope(options = {})
  if (scopes = Array(acts_as_nested_set_options[:scope])).any?
    options[:conditions] = scopes.inject({}) do |conditions,attr|
      conditions.merge attr => self[attr]
    end
  end

  self.class.base_class.unscoped.nested_set_scope options
end
nested_set_scope_without_default_scope(*args) click to toggle source

Separate an other `nested_set_scope` for unscoped model because normal query still need activerecord `default_scope` Only activerecord callbacks need unscoped model to handle the nested set records And class level `nested_set_scope` seems just for query `root` `child` .. etc I think we don't have to provide unscoped `nested_set_scope` in class level.

# File lib/awesome_nested_set/model.rb, line 156
def nested_set_scope_without_default_scope(*args)
  self.class.unscoped do
    nested_set_scope(*args)
  end
end
parent_id(target = self) click to toggle source

Any instance method that returns a collection makes use of Rails 2.1's named_scope (which is bundled for Rails 2.0), so it can be treated as a finder.

category.self_and_descendants.count
category.ancestors.find(:all, :conditions => "name like '%foo%'")

Value of the parent column

# File lib/awesome_nested_set/model.rb, line 105
def parent_id(target = self)
  target[parent_column_name]
end
primary_id(target = self) click to toggle source
# File lib/awesome_nested_set/model.rb, line 109
def primary_id(target = self)
  target[primary_column_name]
end
right(target = self) click to toggle source

Value of the right column

# File lib/awesome_nested_set/model.rb, line 119
def right(target = self)
  target[right_column_name]
end
root?() click to toggle source

Returns true if this is a root node.

# File lib/awesome_nested_set/model.rb, line 124
def root?
  parent_id.nil?
end
to_text() click to toggle source
# File lib/awesome_nested_set/model.rb, line 162
def to_text
  self_and_descendants.map do |node|
    "#{'*'*(node.level+1)} #{node.primary_id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})"
  end.join("\n")
end

Protected Instance Methods

change_descendants_depth!(diff) click to toggle source
# File lib/awesome_nested_set/model.rb, line 228
def change_descendants_depth!(diff)
  if !leaf? && diff != 0
    sign = "++-"[diff <=> 0]
    descendants.update_all("#{quoted_depth_column_name} = #{quoted_depth_column_name} #{sign} #{diff.abs}")
  end
end
has_depth_column?() click to toggle source
# File lib/awesome_nested_set/model.rb, line 180
def has_depth_column?
  nested_set_scope.column_names.map(&:to_s).include?(depth_column_name.to_s)
end
reload_nested_set() click to toggle source

reload left, right, and parent

# File lib/awesome_nested_set/model.rb, line 242
def reload_nested_set
  reload(
    :select => "#{quoted_left_column_full_name}, #{quoted_right_column_full_name}, #{quoted_parent_column_full_name}",
    :lock => true
  )
end
reload_target(target, position) click to toggle source
# File lib/awesome_nested_set/model.rb, line 249
def reload_target(target, position)
  if target.is_a? self.class.base_class
    target.reload
  elsif position != :root
    nested_set_scope.where(primary_column_name => target).first!
  end
end
right_most_bound() click to toggle source
# File lib/awesome_nested_set/model.rb, line 190
def right_most_bound
  @right_most_bound ||= begin
    return 0 if right_most_node.nil?

    right_most_node.lock!
    right_most_node[right_column_name] || 0
  end
end
right_most_node() click to toggle source
# File lib/awesome_nested_set/model.rb, line 184
def right_most_node
  @right_most_node ||= nested_set_scope(
    :order => "#{quoted_right_column_full_name} desc"
  ).first
end
set_default_left_and_right() click to toggle source
# File lib/awesome_nested_set/model.rb, line 235
def set_default_left_and_right
  # adds the new node to the right of all existing nodes
  self[left_column_name] = right_most_bound + 1
  self[right_column_name] = right_most_bound + 2
end
set_depth!() click to toggle source
# File lib/awesome_nested_set/model.rb, line 199
def set_depth!
  return unless has_depth_column?

  in_tenacious_transaction do
    reload
    update_depth(level)
  end
end
set_depth_for_self_and_descendants!() click to toggle source
# File lib/awesome_nested_set/model.rb, line 208
def set_depth_for_self_and_descendants!
  return unless has_depth_column?

  in_tenacious_transaction do
    reload
    self_and_descendants.select(primary_column_name).lock(true)
    old_depth = self[depth_column_name] || 0
    new_depth = level
    update_depth(new_depth)
    change_descendants_depth!(new_depth - old_depth)
    new_depth
  end
end
store_new_parent() click to toggle source
# File lib/awesome_nested_set/model.rb, line 175
def store_new_parent
  @move_to_new_parent_id = send("#{parent_column_name}_changed?") ? parent_id : false
  true # force callback to return true
end
update_depth(depth) click to toggle source
# File lib/awesome_nested_set/model.rb, line 222
def update_depth(depth)
  nested_set_scope.primary_key_scope(primary_id).
      update_all(["#{quoted_depth_column_name} = ?", depth])
  self[depth_column_name] = depth
end
without_self(scope) click to toggle source
# File lib/awesome_nested_set/model.rb, line 170
def without_self(scope)
  return scope if new_record?
  scope.where(["#{self.class.quoted_table_name}.#{self.class.quoted_primary_column_name} != ?", self.primary_id])
end