awesome_nested_set 1.4.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ 2.0.0.pre
2
+ * Expect Rails 3
3
+ * Changed how callbacks work. Returning false in a before_move action does not block save operations. Use a validation or exception in the callback if you need that.
4
+ * Switched to RSpec
5
+ * Remove use of Comparable
@@ -1,4 +1,4 @@
1
- Copyright (c) 2007 [name of plugin creator]
1
+ Copyright (c) 2007-2011 Collective Idea
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,6 +1,8 @@
1
1
  = AwesomeNestedSet
2
2
 
3
- Awesome Nested Set is an implementation of the nested set pattern for ActiveRecord models. It is replacement for acts_as_nested_set and BetterNestedSet, but awesomer. It supports Rails 2.1 and later.
3
+ Awesome Nested Set is an implementation of the nested set pattern for ActiveRecord models. It is replacement for acts_as_nested_set and BetterNestedSet, but more awesome.
4
+
5
+ Version 2 supports Rails 3. Gem versions prior to 2.0 support Rails 2.
4
6
 
5
7
  == What makes this so awesome?
6
8
 
@@ -8,10 +10,10 @@ This is a new implementation of nested set based off of BetterNestedSet that fix
8
10
 
9
11
  == Installation
10
12
 
11
- Install as a plugin:
13
+ Add to your Gemfile:
14
+
15
+ gem 'awesome_nested_set'
12
16
 
13
- script/plugin install git://github.com/collectiveidea/awesome_nested_set.git
14
-
15
17
  == Usage
16
18
 
17
19
  To make use of awesome_nested_set, your model needs to have 3 fields: lft, rgt, and parent_id:
@@ -36,20 +38,20 @@ Enable the nested set functionality by declaring acts_as_nested_set on your mode
36
38
  class Category < ActiveRecord::Base
37
39
  acts_as_nested_set
38
40
  end
39
-
40
- Run `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet::SingletonMethods for more info.
41
+
42
+ Run `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet::Model::SingletonMethods for more info.
41
43
 
42
44
  == Conversion from other trees
43
45
 
44
46
  Coming from acts_as_tree or another system where you only have a parent_id? No problem. Simply add the lft & rgt fields as above, and then run
45
47
 
46
48
  Category.rebuild!
47
-
48
- Your tree be converted to a valid nested set. Awesome!
49
+
50
+ Your tree will be converted to a valid nested set. Awesome!
49
51
 
50
52
  == View Helper
51
53
 
52
- The view helper is called #nested_set_options.
54
+ The view helper is called #nested_set_options.
53
55
 
54
56
  Example usage:
55
57
 
@@ -61,12 +63,7 @@ See CollectiveIdea::Acts::NestedSet::Helper for more information about the helpe
61
63
 
62
64
  == References
63
65
 
64
- You can learn more about nested sets at:
65
-
66
- http://www.dbmsmag.com/9603d06.html
67
- http://threebit.net/tutorials/nestedset/tutorial1.html
68
- http://api.rubyonrails.com/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html
69
- http://opensource.symetrie.com/trac/better_nested_set/
66
+ You can learn more about nested sets at: http://threebit.net/tutorials/nestedset/tutorial1.html
70
67
 
71
68
  == How to contribute
72
69
 
@@ -1,578 +1,7 @@
1
- module CollectiveIdea #:nodoc:
2
- module Acts #:nodoc:
3
- module NestedSet #:nodoc:
4
- def self.included(base)
5
- base.extend(SingletonMethods)
6
- end
1
+ require 'awesome_nested_set/awesome_nested_set'
2
+ ActiveRecord::Base.send :extend, CollectiveIdea::Acts::NestedSet
7
3
 
8
- # This acts provides Nested Set functionality. Nested Set is a smart way to implement
9
- # an _ordered_ tree, with the added feature that you can select the children and all of their
10
- # descendants with a single query. The drawback is that insertion or move need some complex
11
- # sql queries. But everything is done here by this module!
12
- #
13
- # Nested sets are appropriate each time you want either an orderd tree (menus,
14
- # commercial categories) or an efficient way of querying big trees (threaded posts).
15
- #
16
- # == API
17
- #
18
- # Methods names are aligned with acts_as_tree as much as possible to make replacment from one
19
- # by another easier.
20
- #
21
- # item.children.create(:name => "child1")
22
- #
23
- module SingletonMethods
24
- # Configuration options are:
25
- #
26
- # * +:parent_column+ - specifies the column name to use for keeping the position integer (default: parent_id)
27
- # * +:left_column+ - column name for left boundry data, default "lft"
28
- # * +:right_column+ - column name for right boundry data, default "rgt"
29
- # * +:scope+ - restricts what is to be considered a list. Given a symbol, it'll attach "_id"
30
- # (if it hasn't been already) and use that as the foreign key restriction. You
31
- # can also pass an array to scope by multiple attributes.
32
- # Example: <tt>acts_as_nested_set :scope => [:notable_id, :notable_type]</tt>
33
- # * +:dependent+ - behavior for cascading destroy. If set to :destroy, all the
34
- # child objects are destroyed alongside this object by calling their destroy
35
- # method. If set to :delete_all (default), all the child objects are deleted
36
- # without calling their destroy method.
37
- #
38
- # See CollectiveIdea::Acts::NestedSet::ClassMethods for a list of class methods and
39
- # CollectiveIdea::Acts::NestedSet::InstanceMethods for a list of instance methods added
40
- # to acts_as_nested_set models
41
- def acts_as_nested_set(options = {})
42
- options = {
43
- :parent_column => 'parent_id',
44
- :left_column => 'lft',
45
- :right_column => 'rgt',
46
- :dependent => :delete_all, # or :destroy
47
- }.merge(options)
48
-
49
- if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/
50
- options[:scope] = "#{options[:scope]}_id".intern
51
- end
52
-
53
- write_inheritable_attribute :acts_as_nested_set_options, options
54
- class_inheritable_reader :acts_as_nested_set_options
55
-
56
- unless self.is_a?(ClassMethods)
57
- include Comparable
58
- include Columns
59
- include InstanceMethods
60
- extend Columns
61
- extend ClassMethods
62
-
63
- belongs_to :parent, :class_name => self.base_class.to_s,
64
- :foreign_key => parent_column_name
65
- has_many :children, :class_name => self.base_class.to_s,
66
- :foreign_key => parent_column_name, :order => quoted_left_column_name
67
-
68
- attr_accessor :skip_before_destroy
69
-
70
- # no bulk assignment
71
- if accessible_attributes.blank?
72
- attr_protected left_column_name.intern, right_column_name.intern
73
- end
74
-
75
- before_create :set_default_left_and_right
76
- before_save :store_new_parent
77
- after_save :move_to_new_parent
78
- before_destroy :destroy_descendants
79
-
80
- # no assignment to structure fields
81
- [left_column_name, right_column_name].each do |column|
82
- module_eval <<-"end_eval", __FILE__, __LINE__
83
- def #{column}=(x)
84
- raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{column}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead."
85
- end
86
- end_eval
87
- end
88
-
89
- named_scope :roots, :conditions => {parent_column_name => nil}, :order => quoted_left_column_name
90
- named_scope :leaves, :conditions => "#{quoted_right_column_name} - #{quoted_left_column_name} = 1", :order => quoted_left_column_name
91
-
92
- define_callbacks("before_move", "after_move")
93
- end
94
-
95
- end
96
-
97
- end
98
-
99
- module ClassMethods
100
-
101
- # Returns the first root
102
- def root
103
- roots.find(:first)
104
- end
105
-
106
- def valid?
107
- left_and_rights_valid? && no_duplicates_for_columns? && all_roots_valid?
108
- end
109
-
110
- def left_and_rights_valid?
111
- count(
112
- :joins => "LEFT OUTER JOIN #{quoted_table_name} AS parent ON " +
113
- "#{quoted_table_name}.#{quoted_parent_column_name} = parent.#{primary_key}",
114
- :conditions =>
115
- "#{quoted_table_name}.#{quoted_left_column_name} IS NULL OR " +
116
- "#{quoted_table_name}.#{quoted_right_column_name} IS NULL OR " +
117
- "#{quoted_table_name}.#{quoted_left_column_name} >= " +
118
- "#{quoted_table_name}.#{quoted_right_column_name} OR " +
119
- "(#{quoted_table_name}.#{quoted_parent_column_name} IS NOT NULL AND " +
120
- "(#{quoted_table_name}.#{quoted_left_column_name} <= parent.#{quoted_left_column_name} OR " +
121
- "#{quoted_table_name}.#{quoted_right_column_name} >= parent.#{quoted_right_column_name}))"
122
- ) == 0
123
- end
124
-
125
- def no_duplicates_for_columns?
126
- scope_string = Array(acts_as_nested_set_options[:scope]).map do |c|
127
- connection.quote_column_name(c)
128
- end.push(nil).join(", ")
129
- [quoted_left_column_name, quoted_right_column_name].all? do |column|
130
- # No duplicates
131
- find(:first,
132
- :select => "#{scope_string}#{column}, COUNT(#{column})",
133
- :group => "#{scope_string}#{column}
134
- HAVING COUNT(#{column}) > 1").nil?
135
- end
136
- end
137
-
138
- # Wrapper for each_root_valid? that can deal with scope.
139
- def all_roots_valid?
140
- if acts_as_nested_set_options[:scope]
141
- roots(:group => scope_column_names).group_by{|record| scope_column_names.collect{|col| record.send(col.to_sym)}}.all? do |scope, grouped_roots|
142
- each_root_valid?(grouped_roots)
143
- end
144
- else
145
- each_root_valid?(roots)
146
- end
147
- end
148
-
149
- def each_root_valid?(roots_to_validate)
150
- left = right = 0
151
- roots_to_validate.all? do |root|
152
- returning(root.left > left && root.right > right) do
153
- left = root.left
154
- right = root.right
155
- end
156
- end
157
- end
158
-
159
- # Rebuilds the left & rights if unset or invalid. Also very useful for converting from acts_as_tree.
160
- def rebuild!
161
- # Don't rebuild a valid tree.
162
- return true if valid?
163
-
164
- scope = lambda{|node|}
165
- if acts_as_nested_set_options[:scope]
166
- scope = lambda{|node|
167
- scope_column_names.inject(""){|str, column_name|
168
- str << "AND #{connection.quote_column_name(column_name)} = #{connection.quote(node.send(column_name.to_sym))} "
169
- }
170
- }
171
- end
172
- indices = {}
173
-
174
- set_left_and_rights = lambda do |node|
175
- # set left
176
- node[left_column_name] = indices[scope.call(node)] += 1
177
- # find
178
- find(:all, :conditions => ["#{quoted_parent_column_name} = ? #{scope.call(node)}", node], :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, id").each{|n| set_left_and_rights.call(n) }
179
- # set right
180
- node[right_column_name] = indices[scope.call(node)] += 1
181
- node.save!
182
- end
183
-
184
- # Find root node(s)
185
- root_nodes = find(:all, :conditions => "#{quoted_parent_column_name} IS NULL", :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, id").each do |root_node|
186
- # setup index for this scope
187
- indices[scope.call(root_node)] ||= 0
188
- set_left_and_rights.call(root_node)
189
- end
190
- end
191
-
192
- # Iterates over tree elements and determines the current level in the tree.
193
- # Only accepts default ordering, odering by an other column than lft
194
- # does not work. This method is much more efficent than calling level
195
- # because it doesn't require any additional database queries.
196
- #
197
- # Example:
198
- # Category.each_with_level(Category.root.self_and_descendants) do |o, level|
199
- #
200
- def each_with_level(objects)
201
- path = [nil]
202
- objects.each do |o|
203
- if o.parent_id != path.last
204
- # we are on a new level, did we decent or ascent?
205
- if path.include?(o.parent_id)
206
- # remove wrong wrong tailing paths elements
207
- path.pop while path.last != o.parent_id
208
- else
209
- path << o.parent_id
210
- end
211
- end
212
- yield(o, path.length - 1)
213
- end
214
- end
215
- end
216
-
217
- # Mixed into both classes and instances to provide easy access to the column names
218
- module Columns
219
- def left_column_name
220
- acts_as_nested_set_options[:left_column]
221
- end
222
-
223
- def right_column_name
224
- acts_as_nested_set_options[:right_column]
225
- end
226
-
227
- def parent_column_name
228
- acts_as_nested_set_options[:parent_column]
229
- end
230
-
231
- def scope_column_names
232
- Array(acts_as_nested_set_options[:scope])
233
- end
234
-
235
- def quoted_left_column_name
236
- connection.quote_column_name(left_column_name)
237
- end
238
-
239
- def quoted_right_column_name
240
- connection.quote_column_name(right_column_name)
241
- end
242
-
243
- def quoted_parent_column_name
244
- connection.quote_column_name(parent_column_name)
245
- end
246
-
247
- def quoted_scope_column_names
248
- scope_column_names.collect {|column_name| connection.quote_column_name(column_name) }
249
- end
250
- end
251
-
252
- # 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.
253
- #
254
- # category.self_and_descendants.count
255
- # category.ancestors.find(:all, :conditions => "name like '%foo%'")
256
- module InstanceMethods
257
- # Value of the parent column
258
- def parent_id
259
- self[parent_column_name]
260
- end
261
-
262
- # Value of the left column
263
- def left
264
- self[left_column_name]
265
- end
266
-
267
- # Value of the right column
268
- def right
269
- self[right_column_name]
270
- end
271
-
272
- # Returns true if this is a root node.
273
- def root?
274
- parent_id.nil?
275
- end
276
-
277
- def leaf?
278
- !new_record? && right - left == 1
279
- end
280
-
281
- # Returns true is this is a child node
282
- def child?
283
- !parent_id.nil?
284
- end
285
-
286
- # order by left column
287
- def <=>(x)
288
- left <=> x.left
289
- end
290
-
291
- # Redefine to act like active record
292
- def ==(comparison_object)
293
- comparison_object.equal?(self) ||
294
- (comparison_object.instance_of?(self.class) &&
295
- comparison_object.id == id &&
296
- !comparison_object.new_record?)
297
- end
298
-
299
- # Returns root
300
- def root
301
- self_and_ancestors.find(:first)
302
- end
303
-
304
- # Returns the array of all parents and self
305
- def self_and_ancestors
306
- nested_set_scope.scoped :conditions => [
307
- "#{self.class.quoted_table_name}.#{quoted_left_column_name} <= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} >= ?", left, right
308
- ]
309
- end
310
-
311
- # Returns an array of all parents
312
- def ancestors
313
- without_self self_and_ancestors
314
- end
315
-
316
- # Returns the array of all children of the parent, including self
317
- def self_and_siblings
318
- nested_set_scope.scoped :conditions => {parent_column_name => parent_id}
319
- end
320
-
321
- # Returns the array of all children of the parent, except self
322
- def siblings
323
- without_self self_and_siblings
324
- end
325
-
326
- # Returns a set of all of its nested children which do not have children
327
- def leaves
328
- descendants.scoped :conditions => "#{self.class.quoted_table_name}.#{quoted_right_column_name} - #{self.class.quoted_table_name}.#{quoted_left_column_name} = 1"
329
- end
330
-
331
- # Returns the level of this object in the tree
332
- # root level is 0
333
- def level
334
- parent_id.nil? ? 0 : ancestors.count
335
- end
336
-
337
- # Returns a set of itself and all of its nested children
338
- def self_and_descendants
339
- nested_set_scope.scoped :conditions => [
340
- "#{self.class.quoted_table_name}.#{quoted_left_column_name} >= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} <= ?", left, right
341
- ]
342
- end
343
-
344
- # Returns a set of all of its children and nested children
345
- def descendants
346
- without_self self_and_descendants
347
- end
348
-
349
- def is_descendant_of?(other)
350
- other.left < self.left && self.left < other.right && same_scope?(other)
351
- end
352
-
353
- def is_or_is_descendant_of?(other)
354
- other.left <= self.left && self.left < other.right && same_scope?(other)
355
- end
356
-
357
- def is_ancestor_of?(other)
358
- self.left < other.left && other.left < self.right && same_scope?(other)
359
- end
360
-
361
- def is_or_is_ancestor_of?(other)
362
- self.left <= other.left && other.left < self.right && same_scope?(other)
363
- end
364
-
365
- # Check if other model is in the same scope
366
- def same_scope?(other)
367
- Array(acts_as_nested_set_options[:scope]).all? do |attr|
368
- self.send(attr) == other.send(attr)
369
- end
370
- end
371
-
372
- # Find the first sibling to the left
373
- def left_sibling
374
- siblings.find(:first, :conditions => ["#{self.class.quoted_table_name}.#{quoted_left_column_name} < ?", left],
375
- :order => "#{self.class.quoted_table_name}.#{quoted_left_column_name} DESC")
376
- end
377
-
378
- # Find the first sibling to the right
379
- def right_sibling
380
- siblings.find(:first, :conditions => ["#{self.class.quoted_table_name}.#{quoted_left_column_name} > ?", left])
381
- end
382
-
383
- # Shorthand method for finding the left sibling and moving to the left of it.
384
- def move_left
385
- move_to_left_of left_sibling
386
- end
387
-
388
- # Shorthand method for finding the right sibling and moving to the right of it.
389
- def move_right
390
- move_to_right_of right_sibling
391
- end
392
-
393
- # Move the node to the left of another node (you can pass id only)
394
- def move_to_left_of(node)
395
- move_to node, :left
396
- end
397
-
398
- # Move the node to the left of another node (you can pass id only)
399
- def move_to_right_of(node)
400
- move_to node, :right
401
- end
402
-
403
- # Move the node to the child of another node (you can pass id only)
404
- def move_to_child_of(node)
405
- move_to node, :child
406
- end
407
-
408
- # Move the node to root nodes
409
- def move_to_root
410
- move_to nil, :root
411
- end
412
-
413
- def move_possible?(target)
414
- self != target && # Can't target self
415
- same_scope?(target) && # can't be in different scopes
416
- # !(left..right).include?(target.left..target.right) # this needs tested more
417
- # detect impossible move
418
- !((left <= target.left && right >= target.left) or (left <= target.right && right >= target.right))
419
- end
420
-
421
- def to_text
422
- self_and_descendants.map do |node|
423
- "#{'*'*(node.level+1)} #{node.id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})"
424
- end.join("\n")
425
- end
426
-
427
- protected
428
-
429
- def without_self(scope)
430
- scope.scoped :conditions => ["#{self.class.quoted_table_name}.#{self.class.primary_key} != ?", self]
431
- end
432
-
433
- # All nested set queries should use this nested_set_scope, which performs finds on
434
- # the base ActiveRecord class, using the :scope declared in the acts_as_nested_set
435
- # declaration.
436
- def nested_set_scope
437
- options = {:order => quoted_left_column_name}
438
- scopes = Array(acts_as_nested_set_options[:scope])
439
- options[:conditions] = scopes.inject({}) do |conditions,attr|
440
- conditions.merge attr => self[attr]
441
- end unless scopes.empty?
442
- self.class.base_class.scoped options
443
- end
444
-
445
- def store_new_parent
446
- @move_to_new_parent_id = send("#{parent_column_name}_changed?") ? parent_id : false
447
- true # force callback to return true
448
- end
449
-
450
- def move_to_new_parent
451
- if @move_to_new_parent_id.nil?
452
- move_to_root
453
- elsif @move_to_new_parent_id
454
- move_to_child_of(@move_to_new_parent_id)
455
- end
456
- end
457
-
458
- # on creation, set automatically lft and rgt to the end of the tree
459
- def set_default_left_and_right
460
- maxright = nested_set_scope.maximum(right_column_name) || 0
461
- # adds the new node to the right of all existing nodes
462
- self[left_column_name] = maxright + 1
463
- self[right_column_name] = maxright + 2
464
- end
465
-
466
- # Prunes a branch off of the tree, shifting all of the elements on the right
467
- # back to the left so the counts still work.
468
- def destroy_descendants
469
- return if right.nil? || left.nil? || skip_before_destroy
470
-
471
- self.class.base_class.transaction do
472
- if acts_as_nested_set_options[:dependent] == :destroy
473
- descendants.each do |model|
474
- model.skip_before_destroy = true
475
- model.destroy
476
- end
477
- else
478
- nested_set_scope.delete_all(
479
- ["#{quoted_left_column_name} > ? AND #{quoted_right_column_name} < ?",
480
- left, right]
481
- )
482
- end
483
-
484
- # update lefts and rights for remaining nodes
485
- diff = right - left + 1
486
- nested_set_scope.update_all(
487
- ["#{quoted_left_column_name} = (#{quoted_left_column_name} - ?)", diff],
488
- ["#{quoted_left_column_name} > ?", right]
489
- )
490
- nested_set_scope.update_all(
491
- ["#{quoted_right_column_name} = (#{quoted_right_column_name} - ?)", diff],
492
- ["#{quoted_right_column_name} > ?", right]
493
- )
494
-
495
- # Don't allow multiple calls to destroy to corrupt the set
496
- self.skip_before_destroy = true
497
- end
498
- end
499
-
500
- # reload left, right, and parent
501
- def reload_nested_set
502
- reload(:select => "#{quoted_left_column_name}, " +
503
- "#{quoted_right_column_name}, #{quoted_parent_column_name}")
504
- end
505
-
506
- def move_to(target, position)
507
- raise ActiveRecord::ActiveRecordError, "You cannot move a new node" if self.new_record?
508
- return if run_callbacks(:before_move) == false
509
- transaction do
510
- if target.is_a? self.class.base_class
511
- target.reload_nested_set
512
- elsif position != :root
513
- # load object if node is not an object
514
- target = nested_set_scope.find(target)
515
- end
516
- self.reload_nested_set
517
-
518
- unless position == :root || move_possible?(target)
519
- raise ActiveRecord::ActiveRecordError, "Impossible move, target node cannot be inside moved tree."
520
- end
521
-
522
- bound = case position
523
- when :child; target[right_column_name]
524
- when :left; target[left_column_name]
525
- when :right; target[right_column_name] + 1
526
- when :root; 1
527
- else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left, :right or :root ('#{position}' received)."
528
- end
529
-
530
- if bound > self[right_column_name]
531
- bound = bound - 1
532
- other_bound = self[right_column_name] + 1
533
- else
534
- other_bound = self[left_column_name] - 1
535
- end
536
-
537
- # there would be no change
538
- return if bound == self[right_column_name] || bound == self[left_column_name]
539
-
540
- # we have defined the boundaries of two non-overlapping intervals,
541
- # so sorting puts both the intervals and their boundaries in order
542
- a, b, c, d = [self[left_column_name], self[right_column_name], bound, other_bound].sort
543
-
544
- new_parent = case position
545
- when :child; target.id
546
- when :root; nil
547
- else target[parent_column_name]
548
- end
549
-
550
- self.class.base_class.update_all([
551
- "#{quoted_left_column_name} = CASE " +
552
- "WHEN #{quoted_left_column_name} BETWEEN :a AND :b " +
553
- "THEN #{quoted_left_column_name} + :d - :b " +
554
- "WHEN #{quoted_left_column_name} BETWEEN :c AND :d " +
555
- "THEN #{quoted_left_column_name} + :a - :c " +
556
- "ELSE #{quoted_left_column_name} END, " +
557
- "#{quoted_right_column_name} = CASE " +
558
- "WHEN #{quoted_right_column_name} BETWEEN :a AND :b " +
559
- "THEN #{quoted_right_column_name} + :d - :b " +
560
- "WHEN #{quoted_right_column_name} BETWEEN :c AND :d " +
561
- "THEN #{quoted_right_column_name} + :a - :c " +
562
- "ELSE #{quoted_right_column_name} END, " +
563
- "#{quoted_parent_column_name} = CASE " +
564
- "WHEN #{self.class.base_class.primary_key} = :id THEN :new_parent " +
565
- "ELSE #{quoted_parent_column_name} END",
566
- {:a => a, :b => b, :c => c, :d => d, :id => self.id, :new_parent => new_parent}
567
- ], nested_set_scope.proxy_options[:conditions])
568
- end
569
- target.reload_nested_set if target
570
- self.reload_nested_set
571
- run_callbacks(:after_move)
572
- end
573
-
574
- end
575
-
576
- end
577
- end
578
- end
4
+ if defined?(ActionView)
5
+ require 'awesome_nested_set/helper'
6
+ ActionView::Base.send :include, CollectiveIdea::Acts::NestedSet::Helper
7
+ end