lib/nested_set/base.rb in nested_set-1.5.4 vs lib/nested_set/base.rb in nested_set-1.6.0
- old
+ new
@@ -97,11 +97,11 @@
}
scope :leaves, lambda {
where("#{quoted_right_column_name} - #{quoted_left_column_name} = 1").
order(quoted_left_column_name)
}
- scope :with_depth, proc {|level| where(:depth => level).order("lft") }
+ scope :with_depth, proc {|level| where(:depth => level).order(quoted_left_column_name) }
define_callbacks :move, :terminator => "result == false"
end
end
end
@@ -111,10 +111,46 @@
# Returns the first root
def root
roots.first
end
+ # Returns arranged nodes hash.
+ # I.e. you have this tree:
+ #
+ # 1
+ # 2
+ # 3
+ # 4
+ # 5
+ # 6
+ # 7
+ #
+ # Hash will looks like:
+ #
+ # {1 => {2 => {}, 3 => {4 => {5 => {}}, 6 => {}}}, 7 => {}}
+ #
+ # == Usage:
+ #
+ # Categories.arrange
+ # Categories.find(42).children.arrange
+ # Categories.find(42).descendants.arrange
+ # Categories.find(42).self_and_descendants.arrange
+ #
+ # This arranged hash can be rendered with recursive render_tree helper
+ def arrange
+ arranged = ActiveSupport::OrderedHash.new
+ insertion_points = [arranged]
+ depth = 0
+ order(quoted_left_column_name).each_with_level do |node, level|
+ insertion_points.push insertion_points.last.values.last if level > depth
+ (depth - level).times { insertion_points.pop } if level < depth
+ insertion_points.last.merge! node => ActiveSupport::OrderedHash.new
+ depth = level
+ end
+ arranged
+ end
+
def valid?
left_and_rights_valid? && no_duplicates_for_columns? && all_roots_valid?
end
def left_and_rights_valid?
@@ -208,22 +244,20 @@
# because it doesn't require any additional database queries.
#
# Example:
# Category.each_with_level(Category.root.self_and_descendants) do |o, level|
#
- def each_with_level(objects)
- path = [nil]
- objects.each do |o|
- if o.parent_id != path.last
- # we are on a new level, did we decent or ascent?
- if path.include?(o.parent_id)
- # remove wrong wrong tailing paths elements
- path.pop while path.last != o.parent_id
- else
- path << o.parent_id
- end
+
+ def each_with_level(objects = nil)
+ levels = []
+ (objects || scoped).each do |i|
+ if level = levels.index(i.parent_id)
+ levels.slice!((level + 1)..-1)
+ else
+ levels << i.parent_id
+ level = levels.size - 1
end
- yield(o, path.length - 1)
+ yield(i, level)
end
end
def before_move(*args, &block)
set_callback :move, :before, *args, &block