Module: ActiveRecord::Acts::NestedSet::InstanceMethods

Defined in:
lib/active_record/acts/nested_set.rb

Instance Method Summary collapse

Instance Method Details

#add_child(child) ⇒ Object

Adds a child to this object in the tree. If this object hasn’t been initialized, it gets set up as a root node. Otherwise, this method will update all of the other elements in the tree and shift them to the right, keeping everything balanced.



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/active_record/acts/nested_set.rb', line 140

def add_child( child )     
  self.reload
  child.reload

  if child.root?
    raise "Adding sub-tree isn\'t currently supported"
  else
    if ( (self[left_col_name] == nil) || (self[right_col_name] == nil) )
      # Looks like we're now the root node!  Woo
      self[left_col_name] = 1
      self[right_col_name] = 4
      
      # What do to do about validation?
      return nil unless self.save
      
      child[parent_column] = self.id
      child[left_col_name] = 2
      child[right_col_name]= 3
      return child.save
    else
      # OK, we need to add and shift everything else to the right
      child[parent_column] = self.id
      right_bound = self[right_col_name]
      child[left_col_name] = right_bound
      child[right_col_name] = right_bound + 1
      self[right_col_name] += 2
      self.class.base_class.transaction {
        self.class.base_class.update_all( "#{left_col_name} = (#{left_col_name} + 2)",  "#{scope_condition} AND #{left_col_name} >= #{right_bound}" )
        self.class.base_class.update_all( "#{right_col_name} = (#{right_col_name} + 2)",  "#{scope_condition} AND #{right_col_name} >= #{right_bound}" )
        self.save
        child.save
      }
    end
  end                                   
end

#all_childrenObject

Returns a set of all of its children and nested children



187
188
189
# File 'lib/active_record/acts/nested_set.rb', line 187

def all_children
  self.class.base_class.find(:all, :conditions => "#{scope_condition} AND (#{left_col_name} > #{self[left_col_name]}) and (#{right_col_name} < #{self[right_col_name]})" )
end

#before_destroyObject

Prunes a branch off of the tree, shifting all of the elements on the right back to the left so the counts still work.



198
199
200
201
202
203
204
205
206
207
# File 'lib/active_record/acts/nested_set.rb', line 198

def before_destroy
  return if self[right_col_name].nil? || self[left_col_name].nil?
  dif = self[right_col_name] - self[left_col_name] + 1

  self.class.base_class.transaction {
    self.class.base_class.delete_all( "#{scope_condition} and #{left_col_name} > #{self[left_col_name]} and #{right_col_name} < #{self[right_col_name]}" )
    self.class.base_class.update_all( "#{left_col_name} = (#{left_col_name} - #{dif})",  "#{scope_condition} AND #{left_col_name} >= #{self[right_col_name]}" )
    self.class.base_class.update_all( "#{right_col_name} = (#{right_col_name} - #{dif} )",  "#{scope_condition} AND #{right_col_name} >= #{self[right_col_name]}" )
  }
end

#child?Boolean

Returns true is this is a child node

Returns:

  • (Boolean)


125
126
127
128
# File 'lib/active_record/acts/nested_set.rb', line 125

def child?                          
  parent_id = self[parent_column]
  !(parent_id == 0 || parent_id.nil?) && (self[left_col_name] > 1) && (self[right_col_name] > self[left_col_name])
end

#children_countObject

Returns the number of nested children of this object.



177
178
179
# File 'lib/active_record/acts/nested_set.rb', line 177

def children_count
  return (self[right_col_name] - self[left_col_name] - 1)/2
end

#direct_childrenObject

Returns a set of only this entry’s immediate children



192
193
194
# File 'lib/active_record/acts/nested_set.rb', line 192

def direct_children
  self.class.base_class.find(:all, :conditions => "#{scope_condition} and #{parent_column} = #{self.id}")
end

#full_setObject

Returns a set of itself and all of its nested children



182
183
184
# File 'lib/active_record/acts/nested_set.rb', line 182

def full_set
  self.class.base_class.find(:all, :conditions => "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} and #{self[right_col_name]})" )
end

#root?Boolean

Returns true is this is a root node.

Returns:

  • (Boolean)


119
120
121
122
# File 'lib/active_record/acts/nested_set.rb', line 119

def root?
  parent_id = self[parent_column]
  (parent_id == 0 || parent_id.nil?) && (self[left_col_name] == 1) && (self[right_col_name] > self[left_col_name])
end

#unknown?Boolean

Returns true if we have no idea what this is

Returns:

  • (Boolean)


131
132
133
# File 'lib/active_record/acts/nested_set.rb', line 131

def unknown?
  !root? && !child?
end