class CollectiveIdea::Acts::NestedSet::Move

Attributes

instance[R]
position[R]
target[R]

Public Class Methods

new(target, position, instance) click to toggle source
   # File lib/awesome_nested_set/move.rb
 7 def initialize(target, position, instance)
 8   @target = target
 9   @position = position
10   @instance = instance
11 end

Public Instance Methods

move() click to toggle source
   # File lib/awesome_nested_set/move.rb
13 def move
14   prevent_impossible_move
15 
16   bound, other_bound = get_boundaries
17 
18   # there would be no change
19   return if bound == right || bound == left
20 
21   # we have defined the boundaries of two non-overlapping intervals,
22   # so sorting puts both the intervals and their boundaries in order
23   a, b, c, d = [left, right, bound, other_bound].sort
24 
25   lock_nodes_between! a, d
26 
27   nested_set_scope_without_default_scope.where(where_statement(a, d)).update_all(
28     conditions(a, b, c, d)
29   )
30 end

Private Instance Methods

case_condition_for_direction(column_name) click to toggle source
   # File lib/awesome_nested_set/move.rb
81 def case_condition_for_direction(column_name)
82   column = send(column_name)
83   "#{column} = CASE " +
84     "WHEN #{column} BETWEEN :a AND :b " +
85     "THEN #{column} + :d - :b " +
86     "WHEN #{column} BETWEEN :c AND :d " +
87     "THEN #{column} + :a - :c " +
88     "ELSE #{column} END, "
89 end
case_condition_for_parent() click to toggle source
   # File lib/awesome_nested_set/move.rb
91 def case_condition_for_parent
92   "#{quoted_parent_column_name} = CASE " +
93     "WHEN #{quoted_primary_column_name} = :primary_id THEN :new_parent_id " +
94     "ELSE #{quoted_parent_column_name} END"
95 end
conditions(a, b, c, d) click to toggle source
   # File lib/awesome_nested_set/move.rb
60 def conditions(a, b, c, d)
61   _conditions = case_condition_for_direction(:quoted_left_column_name) +
62                 case_condition_for_direction(:quoted_right_column_name) +
63                 case_condition_for_parent
64 
65   # We want the record to be 'touched' if it timestamps.
66   if @instance.respond_to?(:updated_at)
67     _conditions << ", updated_at = :timestamp"
68   end
69 
70   [
71     _conditions,
72     {
73       :a => a, :b => b, :c => c, :d => d,
74       :primary_id => instance.primary_id,
75       :new_parent_id => new_parent_id,
76       :timestamp => Time.now.utc
77     }
78   ]
79 end
get_boundaries() click to toggle source
    # File lib/awesome_nested_set/move.rb
117 def get_boundaries
118   if (bound = target_bound) > right
119     bound -= 1
120     other_bound = right + 1
121   else
122     other_bound = left - 1
123   end
124   [bound, other_bound]
125 end
lock_nodes_between!(left_bound, right_bound) click to toggle source
    # File lib/awesome_nested_set/move.rb
 97 def lock_nodes_between!(left_bound, right_bound)
 98   # select the rows in the model between a and d, and apply a lock
 99   instance_base_class.default_scoped.nested_set_scope.
100                       right_of(left_bound).left_of_right_side(right_bound).
101                       select(primary_column_name).
102                       lock(true)
103 end
new_parent_id() click to toggle source
    # File lib/awesome_nested_set/move.rb
109 def new_parent_id
110   case position
111   when :child then target.primary_id
112   when :root  then nil
113   else target[parent_column_name]
114   end
115 end
prevent_impossible_move() click to toggle source
    # File lib/awesome_nested_set/move.rb
130 def prevent_impossible_move
131   if !root && !instance.move_possible?(target)
132     error_msg = "Impossible move, target node (#{target.class.name},ID: #{target.id}) 
133       cannot be inside moved tree (#{instance.class.name},ID: #{instance.id})."
134     raise ImpossibleMove, error_msg
135   end
136 end
root() click to toggle source
    # File lib/awesome_nested_set/move.rb
105 def root
106   position == :root
107 end
target_bound() click to toggle source
    # File lib/awesome_nested_set/move.rb
138 def target_bound
139   case position
140   when :child then right(target)
141   when :left  then left(target)
142   when :right then right(target) + 1
143   when :root  then nested_set_scope_without_default_scope.pluck(right_column_name).max + 1
144   else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left, :right or :root ('#{position}' received)."
145   end
146 end
where_statement(left_bound, right_bound) click to toggle source
   # File lib/awesome_nested_set/move.rb
43 def where_statement(left_bound, right_bound)
44   instance_arel_table[left_column_name].between(left_bound..right_bound).
45     or(instance_arel_table[right_column_name].between(left_bound..right_bound))
46 end