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
134 def child?
135   !root?
136 end
leaf?() click to toggle source

Returns true if this is the end of a branch.

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

Value of the left column

    # File lib/awesome_nested_set/model.rb
119 def left(target = self)
120   target[left_column_name]
121 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
146 def nested_set_scope(options = {})
147   add_scope_conditions_to_options(options)
148 
149   self.class.base_class.default_scoped.nested_set_scope options
150 end
nested_set_scope_without_default_scope(options = {}) 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
157 def nested_set_scope_without_default_scope(options = {})
158   add_scope_conditions_to_options(options)
159 
160   self.class.base_class.unscoped.nested_set_scope options
161 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
110 def parent_id(target = self)
111   target[parent_column_name]
112 end
primary_id(target = self) click to toggle source
    # File lib/awesome_nested_set/model.rb
114 def primary_id(target = self)
115   target[primary_column_name]
116 end
right(target = self) click to toggle source

Value of the right column

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

Returns true if this is a root node.

    # File lib/awesome_nested_set/model.rb
129 def root?
130   parent_id.nil?
131 end
to_text() click to toggle source
    # File lib/awesome_nested_set/model.rb
163 def to_text
164   self_and_descendants.map do |node|
165     "#{'*'*(node.level+1)} #{node.primary_id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})"
166   end.join("\n")
167 end

Protected Instance Methods

add_scope_conditions_to_options(options) click to toggle source
    # File lib/awesome_nested_set/model.rb
171 def add_scope_conditions_to_options(options)
172   scopes = scope_column_names
173   return if scopes.empty?
174 
175   options[:conditions] = scopes.map { |attr| [attr, self[attr] ] }.to_h
176 end
change_descendants_depth!(diff) click to toggle source
    # File lib/awesome_nested_set/model.rb
235 def change_descendants_depth!(diff)
236   if !leaf? && diff != 0
237     sign = "++-"[diff <=> 0]
238     descendants.update_all("#{quoted_depth_column_name} = #{quoted_depth_column_name} #{sign} #{diff.abs}")
239   end
240 end
has_depth_column?() click to toggle source
    # File lib/awesome_nested_set/model.rb
188 def has_depth_column?
189   nested_set_scope.column_names.map(&:to_s).include?(depth_column_name.to_s)
190 end
reload_nested_set() click to toggle source

reload left, right, and parent

    # File lib/awesome_nested_set/model.rb
263 def reload_nested_set
264   reload(
265     :select => "#{quoted_left_column_full_name}, #{quoted_right_column_full_name}, #{quoted_parent_column_full_name}",
266     :lock => true
267   )
268 end
reload_target(target, position) click to toggle source
    # File lib/awesome_nested_set/model.rb
270 def reload_target(target, position)
271   if target.is_a? self.class.base_class
272     target.reload
273   elsif position != :root
274     nested_set_scope_without_default_scope.where(primary_column_name => target).first!
275   end
276 end
right_most_bound() click to toggle source
    # File lib/awesome_nested_set/model.rb
198 def right_most_bound
199   @right_most_bound ||= begin
200     return 0 if right_most_node.nil?
201 
202     right_most_node.lock!
203     right_most_node[right_column_name] || 0
204   end
205 end
right_most_node() click to toggle source
    # File lib/awesome_nested_set/model.rb
192 def right_most_node
193   @right_most_node ||= nested_set_scope_without_default_scope(
194     :order => {right_column_name => :desc}
195   ).first
196 end
set_default_left_and_right() click to toggle source
    # File lib/awesome_nested_set/model.rb
256 def set_default_left_and_right
257   # adds the new node to the right of all existing nodes
258   self[left_column_name] = right_most_bound + 1
259   self[right_column_name] = right_most_bound + 2
260 end
set_depth!() click to toggle source
    # File lib/awesome_nested_set/model.rb
207 def set_depth!
208   return unless has_depth_column?
209 
210   in_tenacious_transaction do
211     update_depth(level)
212   end
213 end
set_depth_for_self_and_descendants!() click to toggle source
    # File lib/awesome_nested_set/model.rb
215 def set_depth_for_self_and_descendants!
216   return unless has_depth_column?
217 
218   in_tenacious_transaction do
219     reload
220     self_and_descendants.select(primary_column_name).lock(true)
221     old_depth = self[depth_column_name] || 0
222     new_depth = level
223     update_depth(new_depth)
224     change_descendants_depth!(new_depth - old_depth)
225     new_depth
226   end
227 end
store_new_parent() click to toggle source
    # File lib/awesome_nested_set/model.rb
183 def store_new_parent
184   @move_to_new_parent_id = send("#{parent_column_name}_changed?") ? parent_id : false
185   true # force callback to return true
186 end
update_counter_cache() click to toggle source
    # File lib/awesome_nested_set/model.rb
242 def update_counter_cache
243   return unless acts_as_nested_set_options[:counter_cache]
244 
245   # Decrease the counter for all old parents
246   if old_parent = self.parent
247     old_parent.class.decrement_counter(acts_as_nested_set_options[:counter_cache], old_parent)
248   end
249 
250   # Increase the counter for all new parents
251   if new_parent = self.reload.parent
252     new_parent.class.increment_counter(acts_as_nested_set_options[:counter_cache], new_parent)
253   end
254 end
update_depth(depth) click to toggle source
    # File lib/awesome_nested_set/model.rb
229 def update_depth(depth)
230   nested_set_scope.primary_key_scope(primary_id).
231       update_all(["#{quoted_depth_column_name} = ?", depth])
232   self[depth_column_name] = depth
233 end
without_self(scope) click to toggle source
    # File lib/awesome_nested_set/model.rb
178 def without_self(scope)
179   return scope if new_record?
180   scope.where(["#{self.class.quoted_table_name}.#{self.class.quoted_primary_column_name} != ?", self.primary_id])
181 end