Module: Mongoid::Tree::RationalNumbering

Extended by:
ActiveSupport::Concern
Defined in:
lib/mongoid/tree/rational_numbering.rb

Overview

Mongoid::Tree::RationalNumbering

Provides rational number sorting on your tree structure. This makes it simple to query for a tree given a node in a single query. Given this tree Node 1

Node 1-1
Node 1-2
  Node 1-2-1
  Node 1-2-2
    Node 1-2-2-1
    Node 1-2-2-2
  Node 1-2-3
Node 1-3

Node 2

Node 2-1
  Node 2-1-1
  Node 2-1-2
Node 2-2

Node 3 Node 4

The entire tree can be queried like this: node_2 = Node.where(title: “Node 2”).first node_1.tree returns:

“Node 2”, “Node 2-1”, “Node 2-1-1”, “Node 2-1-2”, “Node 2-2”

Mongoid::Tree doesn’t use rational numbers by default. To enable rational numbering of children include both Mongoid::Tree and Mongoid::Tree::RationalNumbering into your document.

Utility methods

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

@@_disable_timestamp_count =
0

Instance Method Summary collapse

Instance Method Details

#ancestorsMongoid::Criteria

Returns a chainable criteria for this document’s ancestors

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s ancestors



453
454
455
# File 'lib/mongoid/tree/rational_numbering.rb', line 453

def ancestors
  base_class.unscoped { super }
end

#at_bottom?Boolean

Is this the lowest sibling?

Returns:

  • (Boolean)

    Whether the document is the lowest sibling



543
544
545
# File 'lib/mongoid/tree/rational_numbering.rb', line 543

def at_bottom?
  lower_siblings.empty?
end

#at_top?Boolean

Is this the highest sibling?

Returns:

  • (Boolean)

    Whether the document is the highest sibling



534
535
536
# File 'lib/mongoid/tree/rational_numbering.rb', line 534

def at_top?
  higher_siblings.empty?
end

#correct_rational_parent?(nv, dv) ⇒ Boolean

Verifies parent keys from calculation and query

Parameters:

  • nv (Integer)

    The nominator value

  • dv (Integer)

    The denominator value

Returns:

  • (Boolean)

    true for correct, else false



347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'lib/mongoid/tree/rational_numbering.rb', line 347

def correct_rational_parent?(nv, dv)
  q_rational_number = query_ancestor_rational_number
  # puts "  #{self.name} correct_rational_parent? nv: #{nv} dv: #{dv} query_ancestor_rational_number: #{q_rational_number.inspect}"
  if q_rational_number.nil?
    if RationalNumber.new(nv,dv).parent.root?
      return true
    else
      return false
    end
  end
  return true if self.rational_number.parent == q_rational_number
  false
end

#disable_timestamp_callbackvoid

This method returns an undefined value.

Disable the timestamps for the document type, and increase the disable count Will only disable once, even if called multiple times



716
717
718
719
720
721
722
# File 'lib/mongoid/tree/rational_numbering.rb', line 716

def disable_timestamp_callback
  # # puts "Disabling timestamp callback count: #{@@_disable_timestamp_count}"
  if self.respond_to?("updated_at")
    self.class.skip_callback(:update, :before, :set_updated_at ) if @@_disable_timestamp_count == 0
    @@_disable_timestamp_count += 1
  end
end

#enable_timestamp_callbackvoid

This method returns an undefined value.

Enable the timestamps for the document type, and decrease the disable count Will only enable once, even if called multiple times



729
730
731
732
733
734
735
# File 'lib/mongoid/tree/rational_numbering.rb', line 729

def enable_timestamp_callback
  # # puts "Enabling timestamp callback count: #{@@_disable_timestamp_count}"
  if self.respond_to?("updated_at")
    @@_disable_timestamp_count -= 1
    self.class.set_callback(:update, :before, :set_updated_at ) if @@_disable_timestamp_count == 0
  end
end

#first_sibling_in_listMongoid::Document

Returns the highest sibling (could be self)

Returns:

  • (Mongoid::Document)

    The highest sibling



525
526
527
# File 'lib/mongoid/tree/rational_numbering.rb', line 525

def first_sibling_in_list
  siblings_and_self.first
end

#forced_rational_number?Boolean

Was the changed forced?

Returns:

  • (Boolean)


801
802
803
# File 'lib/mongoid/tree/rational_numbering.rb', line 801

def forced_rational_number?
  !!@_forced_rational_number
end

#from_rational_number(rational_number) ⇒ void

This method returns an undefined value.

Convert from rational number and set keys accordingly

Parameters:

  • rational_number (RationalNumber)

    The rational number for this node



440
441
442
443
444
445
446
# File 'lib/mongoid/tree/rational_numbering.rb', line 440

def from_rational_number(rational_number)
  self.rational_number_nv    = rational_number.nv
  self.rational_number_dv    = rational_number.dv
  self.rational_number_snv   = rational_number.snv
  self.rational_number_sdv   = rational_number.sdv
  self.rational_number_value = rational_number.number
end

#higher_siblingsMongoid::Criteria

Returns siblings above the current document. Siblings with a position lower than this document’s position.

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s higher siblings



482
483
484
# File 'lib/mongoid/tree/rational_numbering.rb', line 482

def higher_siblings
  self.siblings.where(:rational_number_value.lt => self.rational_number_value)
end

#initialize(*args) ⇒ void

Initialize the rational tree document



140
141
142
143
144
# File 'lib/mongoid/tree/rational_numbering.rb', line 140

def initialize(*args)
  @_forced_rational_number = false
  @_rational_moving_nodes  = false
  super
end

#last_sibling_in_listMongoid::Document

Returns the lowest sibling (could be self)

Returns:

  • (Mongoid::Document)

    The lowest sibling



516
517
518
# File 'lib/mongoid/tree/rational_numbering.rb', line 516

def last_sibling_in_list
  siblings_and_self.last
end

#lower_siblingsMongoid::Criteria

Returns siblings below the current document. Siblings with a position greater than this document’s position.

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s lower siblings



472
473
474
# File 'lib/mongoid/tree/rational_numbering.rb', line 472

def lower_siblings
  self.siblings.where(:rational_number_value.gt => self.rational_number_value)
end

#move_above(other) ⇒ void

This method returns an undefined value.

Move this node above the specified node

This method changes the node’s parent if nescessary.

Parameters:

  • other (Mongoid::Document)

    document to move this document above



656
657
658
659
660
661
662
663
664
665
666
667
668
669
# File 'lib/mongoid/tree/rational_numbering.rb', line 656

def move_above(other)
  ensure_to_be_sibling_of(other)
  return if other.position == self.position + 1
  @_rational_moving_nodes = true
  # If there are nodes between this and other before move, make sure they are shifted upwards before moving
  _direction = (self.position > other.position ? 1 : -1)
  _position = (_direction < 0 ? other.position + _direction : other.position)
  shift_nodes_position(other, _direction, (_direction > 0 ? false : true))

  # There should not be conflicting nodes at this stage.
  move_to_position(_position)
  save!
  @_rational_moving_nodes = false
end

#move_below(other) ⇒ void

This method returns an undefined value.

Move this node below the specified node

This method changes the node’s parent if nescessary.

Parameters:

  • other (Mongoid::Document)

    document to move this document above



680
681
682
683
684
685
686
687
688
689
690
691
692
693
# File 'lib/mongoid/tree/rational_numbering.rb', line 680

def move_below(other)
  ensure_to_be_sibling_of(other)
  return if other.position + 1 == self.position

  @_rational_moving_nodes = true

  _direction = (self.position > other.position ? 1 : -1)
  _position = (_direction > 0 ? other.position + _direction : other.position)
  shift_nodes_position(other, _direction, (_direction > 0 ? true : false))

  move_to_position(_position)
  save!
  @_rational_moving_nodes = false
end

#move_conflicting_nodes(nv, dv) ⇒ void

This method returns an undefined value.

Move conflicting nodes for a given value

Parameters:

  • nv (Integer)

    The nominator value

  • dv (Integer)

    The denominator value



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/mongoid/tree/rational_numbering.rb', line 308

def move_conflicting_nodes(nv,dv)
  # As we are moving to the position of the conflicting sibling, it all items can be shifted similar to "move_above"

  conflicting_sibling = base_class.where(:rational_number_nv => nv).where(:rational_number_dv => dv).excludes(:id => self.id).first
  if (conflicting_sibling != nil)
  # puts "moving conflicting nodes"
    without_timestamping do
      # ensure_to_be_sibling_of(conflicting_sibling)
      return if conflicting_sibling.position == self.position + 1
      # If there are nodes between this and conflicting_sibling before move, make sure their position shifted before moving
      _direction = (self.position > conflicting_sibling.position ? 1 : -1)
      _position = (_direction < 0 ? conflicting_sibling.position + _direction : conflicting_sibling.position)
      shift_nodes_position(conflicting_sibling, _direction, (_direction > 0 ? false : true))
    end
  end
end

#move_downvoid

This method returns an undefined value.

Move this node one position down



584
585
586
587
588
589
# File 'lib/mongoid/tree/rational_numbering.rb', line 584

def move_down
  unless at_bottom?
    next_sibling = lower_siblings.first
    switch_with_sibling(next_sibling) unless next_sibling.nil?
  end
end

#move_node_and_save_if_changed(node, new_rational_number) ⇒ void

This method returns an undefined value.

Move a node to given rational number and save/update the node



416
417
418
419
420
421
422
# File 'lib/mongoid/tree/rational_numbering.rb', line 416

def move_node_and_save_if_changed(node, new_rational_number)
  if new_rational_number != node.rational_number
    node.move_to_rational_number(new_rational_number.nv, new_rational_number.dv, {:force => true})
    node.save_with_force_rational_numbers!
    # node.reload # Should caller be responsible for reloading?
  end
end

#move_to_bottomvoid

This method returns an undefined value.

Move this node below all its siblings



562
563
564
565
# File 'lib/mongoid/tree/rational_numbering.rb', line 562

def move_to_bottom
  return true if at_bottom?
  move_below(last_sibling_in_list)
end

#move_to_position(_position, opts = {}) ⇒ void

This method returns an undefined value.

INTERNAL

Move the document to a given position (integer based, starting with 1)

if a document exists on the new position, all siblings are shifted right before moving this document can move without updating conflicting siblings by using :force in options

Parameters:

  • _position (Integer)

    The positional value

  • opts (Hash) (defaults to: {})

    :force (defaults to false)



174
175
176
177
# File 'lib/mongoid/tree/rational_numbering.rb', line 174

def move_to_position(_position, opts = {})
  new_rational_number = parent_rational_number.child_from_position(_position)
  move_to_rational_number(new_rational_number.nv, new_rational_number.dv, opts)
end

#move_to_rational_number(nv, dv, opts = {}) ⇒ void

This method returns an undefined value.

INTERNAL

Move the document to a given rational_number position

if a document exists on the new position, all siblings are shifted right before moving this document can move without updating conflicting siblings by using :ignore_conflicts in options

Parameters:

  • nv (Integer)

    The nominator value

  • dv (Integer)

    The denominator value

  • opts (Hash) (defaults to: {})

    Options: :force (defaults to false)



192
193
194
195
196
197
198
199
200
201
202
# File 'lib/mongoid/tree/rational_numbering.rb', line 192

def move_to_rational_number(nv, dv, opts = {})
  # don't check for conflict if forced move
  move_conflicting_nodes(nv,dv) unless !!opts[:force]

  # shouldn't be any conflicting sibling now...
  self.from_rational_number(RationalNumber.new(nv,dv))
  # if parent_id is unknown, find parent and set correct parent_id
  if self.parent_id.nil? and self.rational_number.root?
    # puts "!!!!!!!!! #{self.name} move_to_rational_number missing parent and NOT root rational number!"
  end
end

#move_to_topvoid

This method returns an undefined value.

Move this node above all its siblings



552
553
554
555
# File 'lib/mongoid/tree/rational_numbering.rb', line 552

def move_to_top
  return true if at_top?
  move_above(first_sibling_in_list)
end

#move_upvoid

This method returns an undefined value.

Move this node one position up



572
573
574
575
576
577
# File 'lib/mongoid/tree/rational_numbering.rb', line 572

def move_up
  unless at_top?
    prev_sibling = higher_siblings.last
    switch_with_sibling(prev_sibling) unless prev_sibling.nil?
  end
end

#moving_nodes?Boolean

Currently moving nodes around?

Returns:

  • (Boolean)


808
809
810
# File 'lib/mongoid/tree/rational_numbering.rb', line 808

def moving_nodes?
  !!@_rational_moving_nodes
end

#parent_exists?(nv, dv) ⇒ Boolean

Check if a parent exists for the given nv/dv values

Will return true if the parent is “root” and the node should be created as a root element

Parameters:

  • nv (Integer)

    The nominator value

  • dv (Integer)

    The denominator value

Returns:

  • (Boolean)

    returns true if the parent exists



289
290
291
292
293
294
295
296
297
# File 'lib/mongoid/tree/rational_numbering.rb', line 289

def parent_exists?(nv,dv)
  q_parent = base_class.where(:rational_number_nv => nv).where(:rational_number_dv => dv).excludes(:id => self.id).first
  if q_parent.nil?
    return true if RationalNumber.new(nv,dv).parent.root?
  else
    return true
  end
  false
end

#parent_rational_numberObject

Get the parent rational number or “root” rational number if no parent



773
774
775
776
777
778
779
# File 'lib/mongoid/tree/rational_numbering.rb', line 773

def parent_rational_number
  if root?
    RationalNumber.new
  else
    self.parent.rational_number
  end
end

#positionObject

Returns the positional value for the current node

@return  The positional value calculated from the rational number



462
463
464
# File 'lib/mongoid/tree/rational_numbering.rb', line 462

def position
  self.rational_number.position
end

#query_ancestor_rational_numberRationalNumber

Query the ancestor rational number

Returns:

  • (RationalNumber)

    returns the rational number for the ancestor or nil for “not found”



331
332
333
334
335
336
# File 'lib/mongoid/tree/rational_numbering.rb', line 331

def query_ancestor_rational_number
  # puts "  #{self.name} query_ancestor_rational_number parent_id: #{self.parent_id}"
  check_parent = base_class.where(:_id => self.parent_id).first
  return nil if (check_parent.nil? || check_parent == [])
  check_parent.rational_number
end

#rational_numberRationalNumber

Convert to rational number

Returns:

  • (RationalNumber)

    The rational number for this node



429
430
431
# File 'lib/mongoid/tree/rational_numbering.rb', line 429

def rational_number
  RationalNumber.new(self.rational_number_nv, self.rational_number_dv, self.rational_number_snv, self.rational_number_sdv)
end

#rekey_childrenvoid

This method returns an undefined value.

Rekey each of the children (usually forcefully if a tree has gone “crazy”)



374
375
376
377
378
379
380
381
382
# File 'lib/mongoid/tree/rational_numbering.rb', line 374

def rekey_children
  _pos = 1
  this_rational_number = self.rational_number
  self.children.each do |child|
    new_rational_number = this_rational_number.child_from_position(_pos)
    move_node_and_save_if_changed(child, new_rational_number)
    _pos += 1
  end
end

#rekey_children?Boolean

Check if children needs to be rekeyed

Returns:

  • (Boolean)


364
365
366
# File 'lib/mongoid/tree/rational_numbering.rb', line 364

def rekey_children?
  persisted? && self.children? && ( self.previous_changes.include?("rational_number_nv") || self.previous_changes.include?("parent_ids") || self.changes.include?("rational_number_nv") || self.changes.include?("parent_ids") )
end

#rekey_former_siblingsvoid

This method returns an undefined value.

Rekey former siblings after a move



400
401
402
403
404
405
406
407
408
# File 'lib/mongoid/tree/rational_numbering.rb', line 400

def rekey_former_siblings
  former_siblings = base_class.where(:parent_id => attribute_was('parent_id')).
                               and(:rational_number_value.gt => (attribute_was('rational_number_value') || 0)).
                               excludes(:id => self.id)
  former_siblings.each do |prev_sibling|
    new_rational_number = prev_sibling.parent_rational_number.child_from_position(prev_sibling.position - 1)
    move_node_and_save_if_changed(prev_sibling, new_rational_number)
  end
end

#rekey_former_siblings?Boolean

Should the former siblings be rekeyed?

Returns:

  • (Boolean)

    true if needed, else false



390
391
392
# File 'lib/mongoid/tree/rational_numbering.rb', line 390

def rekey_former_siblings?
  persisted? && self.previous_changes.include?("parent_id")
end

#save_with_force_rational_numbers!Object

save when forcing rational numbers



815
816
817
818
819
820
# File 'lib/mongoid/tree/rational_numbering.rb', line 815

def save_with_force_rational_numbers!
  # puts "-- Saving #{self.name} #{self.updated_at.utc}" if self.respond_to?("updated_at")
  @_forced_rational_number = true
  self.save!
  @_forced_rational_number = false
end

#set_initial_rational_number?Boolean

Should the initial rational number value

Returns:

  • (Boolean)


794
795
796
# File 'lib/mongoid/tree/rational_numbering.rb', line 794

def set_initial_rational_number?
  self.rational_number_value.nil?
end

#set_rational_number(nv, dv, do_save = true) ⇒ Boolean

This can be used to set a rational number directly The node will be moved to the correct parent

If the given nv/dv does not find an existing parent, it will add an validation error

If the given nv/dv is higher than the last sibling under the parent, the nv/dv will be recalculated to appropriate nv/dv values

Parameters:

  • nv (Integer)

    The nominator value

  • dv (Integer)

    The denominator value

  • do_save (Boolean) (defaults to: true)

    true/false if the model should be saved or just updated

Returns:

  • (Boolean)

    returns the save value or true if do_save is set to false



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/mongoid/tree/rational_numbering.rb', line 220

def set_rational_number(nv,dv, do_save = true)
  # return true of already at the right spot
  # puts "#{self.name} - set_rational_number #{nv}/#{dv} self:#{self.rational_number_nv}/#{self.rational_number_dv}"
  return true if self.rational_number_nv == nv && self.rational_number_dv == dv && (!self.rational_number_nv_changed? && !self.rational_number_dv_changed?)
  # check if parent exist
  # puts "  parent exists: #{parent_exists?(nv,dv).inspect}"
  unless parent_exists?(nv,dv)
    errors.add(:base, I18n.t(:parent_does_not_exist, :scope => [:mongoid, :errors, :messages, :tree, :rational], nv: nv, dv: dv) )
    return false
  end
  # find other/conflicting sibling
  other = base_class.where(:rational_number_nv => nv).where(:rational_number_dv => dv).excludes(:id => self.id).first
  already_sibling_of = other.nil? ? false : self.sibling_of?(other)

  # puts "  conflicting node: #{other.nil? ? '-' : other.name } already_sibling_of :#{already_sibling_of}"
  return false if ensure_to_have_correct_parent(nv,dv) == false

  move_to_rational = RationalNumber.new(nv,dv)

  unless other.nil?
    if already_sibling_of
      # puts "  already sibling of other, so moving down"
      return if other.position == self.position + 1
      # If there are nodes between this and other before move, make sure they are shifted upwards before moving
      _direction = (self.position > other.position ? 1 : -1)
      _position = (_direction < 0 ? other.position + _direction : other.position)
      shift_nodes_position(other, _direction, (_direction > 0 ? false : true))

      # There should not be conflicting nodes at this stage.
      move_to_position(_position)
    else
      # puts "  shifting lower nodes from other"
      shift_lower_nodes_from_other(other, 1)
    end
  else
    # make sure the new position is the next rational value under the parent
    # as there was no "other" to move
    new_parent = base_class.where(:id => self.parent_id).first
    if new_parent.nil?
      # count roots
      root_count = base_class.roots.count
      move_to_rational = RationalNumber.new.child_from_position(root_count+1)
      # puts "  new parent is root root_count: #{root_count} new 'correct position' is : #{move_to_rational.nv}/#{move_to_rational.dv}"
    else
      child_count = new_parent.children.count
      move_to_rational = new_parent.rational_number.child_from_position(child_count+1)
      # puts "  new parent is not root child_count: #{child_count} new 'correct position' is : #{move_to_rational.nv}/#{move_to_rational.dv}"
    end
  end
  move_to_rational_number(move_to_rational.nv, move_to_rational.dv, {:force => true})
  if do_save
    save
  else
    true
  end
end

#shift_lower_nodes_from_other(other, direction) ⇒ void

This method returns an undefined value.

Shift nodes between self and other (or including other) in one or the other direction

Parameters:

  • other (Mongoid::Document)

    Other document to move this document above

  • direction (Integer)

    +1 / -1 for the direction to shift nodes



620
621
622
623
624
625
# File 'lib/mongoid/tree/rational_numbering.rb', line 620

def shift_lower_nodes_from_other(other, direction)
  # puts "#{self.name} shift_lower_nodes_from_other other: #{other.name} direction: #{direction} other.siblings_and_self.count: #{other.siblings_and_self.count}"
  range = [other.rational_number_value, other.siblings_and_self.last.rational_number_value].sort
  nodes_to_shift = other.siblings_and_self.where(:rational_number_value.gte => range.first, :rational_number_value.lte => range.last)
  shift_nodes(nodes_to_shift, direction)
end

#shift_nodes(nodes_to_shift, direction) ⇒ void

This method returns an undefined value.

Shift nodes in a direction

Parameters:

  • nodes_to_shift (Array)

    Array of documents to shift in a given direction

  • direction (Integer)

    +1 / -1 for the direction to shift nodes



635
636
637
638
639
640
641
642
643
644
645
# File 'lib/mongoid/tree/rational_numbering.rb', line 635

def shift_nodes(nodes_to_shift, direction)
  # puts "#{self.name} shift_nodes direction: #{direction}"
  without_timestamping do
    nodes_to_shift.each do |node_to_shift|
      pos = node_to_shift.position + direction
      # puts "  shifting #{node_to_shift.name} from position #{node_to_shift.position} to #{pos}"
      node_to_shift.move_to_position(pos, {:force => true})
      node_to_shift.save_with_force_rational_numbers!
    end
  end
end

#shift_nodes_position(other, direction, exclude_other = false) ⇒ void

This method returns an undefined value.

Shift nodes between self and other (or including other) in one or the other direction

Parameters:

  • other (Mongoid::Document)

    Other document to move this document above

  • direction (Integer)

    +1 / -1 for the direction to shift nodes

  • exclude_other (Boolean) (defaults to: false)

    exclude the other object in the shift or not.



600
601
602
603
604
605
606
607
608
609
610
# File 'lib/mongoid/tree/rational_numbering.rb', line 600

def shift_nodes_position(other, direction, exclude_other = false)
  without_timestamping do
    # puts "#{self.name} shift_nodes_position other: #{other.name} direction #{direction} exclude_other: #{exclude_other}"
    if exclude_other
      nodes_to_shift = siblings_between(other)
    else
      nodes_to_shift = siblings_between_including_other(other)
    end
    shift_nodes(nodes_to_shift, direction)
  end
end

#siblings_between(other) ⇒ Mongoid::Criteria

Returns siblings between the current document and the other document Siblings with a position between this document’s position and the other document’s position.

Parameters:

  • other (Mongoid:Document)

    The other mongoid document

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the documents between this and the other document



494
495
496
497
# File 'lib/mongoid/tree/rational_numbering.rb', line 494

def siblings_between(other)
  range = [self.rational_number_value, other.rational_number_value].sort
  self.siblings.where(:rational_number_value.gt => range.first, :rational_number_value.lt => range.last)
end

#siblings_between_including_other(other) ⇒ Mongoid::Criteria

Return the siblings between this and other + other

Parameters:

  • other (Mongoid:Document)

    The other mongoid document

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the documents between this and the other document



506
507
508
509
# File 'lib/mongoid/tree/rational_numbering.rb', line 506

def siblings_between_including_other(other)
  range = [self.rational_number_value, other.rational_number_value].sort
  self.siblings.where(:rational_number_value.gte => range.first, :rational_number_value.lte => range.last)
end

#treeObject

Get the tree under the given node



825
826
827
828
829
830
# File 'lib/mongoid/tree/rational_numbering.rb', line 825

def tree
  low_rational_number  = self.rational_number_value
  high_rational_number = self.rational_number.parent.child_from_position(self.position+1).number

  base_class.where(:rational_number_value.gt => low_rational_number, :rational_number_value.lt => high_rational_number)
end

#tree_and_selfObject

Get the tree under the given node



835
836
837
838
839
840
# File 'lib/mongoid/tree/rational_numbering.rb', line 835

def tree_and_self
  low_rational_number  = self.rational_number_value
  high_rational_number = self.rational_number.parent.child_from_position(self.position+1).number

  base_class.where(:rational_number_value.gte => low_rational_number, :rational_number_value.lt => high_rational_number)
end

#update_rational_numbervoid

This method returns an undefined value.

Update the rational numbers on the document if changes to parent or rational number has been changed

Should calculate next free nv/dv and set that if parent has changed. (set values to “missing and call missing function should work”)

If there are both changes to nv/dv and parent_id, nv/dv settings takes precedence over parent_id changes



751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
# File 'lib/mongoid/tree/rational_numbering.rb', line 751

def update_rational_number
  if self.rational_number_nv_changed? && self.rational_number_dv_changed? && !self.rational_number_value.nil? && !set_initial_rational_number?
    self.set_rational_number(self.rational_number_nv, self.rational_number_dv, false)
  elsif self.parent_id_changed? || set_initial_rational_number?
    # only changed parent, needs to find next free position
    # Get rational number from new parent

    last_sibling = self.siblings.last

    if (last_sibling.nil?)
      new_rational_number = parent_rational_number.child_from_position(1)
    else
      new_rational_number = parent_rational_number.child_from_position(last_sibling.rational_number.position + 1)
    end

    self.move_to_rational_number(new_rational_number.nv, new_rational_number.dv)
  end
end

#update_rational_number?Boolean

Check if the rational number should be updated

Returns:

  • (Boolean)

    true if it should be updated, else false



787
788
789
# File 'lib/mongoid/tree/rational_numbering.rb', line 787

def update_rational_number?
  (set_initial_rational_number? || self.parent_id_changed? || (self.rational_number_nv_changed? && self.rational_number_dv_changed?)) && !self.forced_rational_number? && !self.moving_nodes?
end

#validate_rational_hierarchyObject

Validate that this document has the correct parent document through a query If not, the parent must be set before setting nv/dv driectly

Returns:

  • true for valid, else false



153
154
155
156
157
158
159
# File 'lib/mongoid/tree/rational_numbering.rb', line 153

def validate_rational_hierarchy
  if self.rational_number_nv_changed? && self.rational_number_dv_changed?
    unless correct_rational_parent?(self.rational_number_nv, self.rational_number_dv)
      errors.add(:base, I18n.t(:cyclic, :scope => [:mongoid, :errors, :messages, :tree]))
    end
  end
end

#without_timestamping(&block) ⇒ void

This method returns an undefined value.

Call block without triggeringtimestamps

Parameters:

  • block

    code block to call



704
705
706
707
708
709
# File 'lib/mongoid/tree/rational_numbering.rb', line 704

def without_timestamping(&block)
  # # puts "without_timestamping: Automagic timpestamping enabled? #{self.class.auto_tree_timestamping}"
  disable_timestamp_callback() if self.class.auto_tree_timestamping
  yield
  enable_timestamp_callback()  if self.class.auto_tree_timestamping
end