acts_as_ordered_tree 1.3.1 → 2.0.0.beta3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/acts_as_ordered_tree.rb +22 -100
- data/lib/acts_as_ordered_tree/adapters.rb +17 -0
- data/lib/acts_as_ordered_tree/adapters/abstract.rb +23 -0
- data/lib/acts_as_ordered_tree/adapters/postgresql.rb +150 -0
- data/lib/acts_as_ordered_tree/adapters/recursive.rb +157 -0
- data/lib/acts_as_ordered_tree/compatibility.rb +22 -0
- data/lib/acts_as_ordered_tree/compatibility/active_record/association_scope.rb +9 -0
- data/lib/acts_as_ordered_tree/compatibility/active_record/default_scoped.rb +19 -0
- data/lib/acts_as_ordered_tree/compatibility/active_record/null_relation.rb +71 -0
- data/lib/acts_as_ordered_tree/compatibility/features.rb +153 -0
- data/lib/acts_as_ordered_tree/deprecate.rb +24 -0
- data/lib/acts_as_ordered_tree/hooks.rb +38 -0
- data/lib/acts_as_ordered_tree/hooks/update.rb +86 -0
- data/lib/acts_as_ordered_tree/instance_methods.rb +92 -453
- data/lib/acts_as_ordered_tree/iterators/arranger.rb +35 -0
- data/lib/acts_as_ordered_tree/iterators/level_calculator.rb +52 -0
- data/lib/acts_as_ordered_tree/iterators/orphans_pruner.rb +58 -0
- data/lib/acts_as_ordered_tree/node.rb +78 -0
- data/lib/acts_as_ordered_tree/node/attributes.rb +48 -0
- data/lib/acts_as_ordered_tree/node/movement.rb +62 -0
- data/lib/acts_as_ordered_tree/node/movements.rb +111 -0
- data/lib/acts_as_ordered_tree/node/predicates.rb +98 -0
- data/lib/acts_as_ordered_tree/node/reloading.rb +49 -0
- data/lib/acts_as_ordered_tree/node/siblings.rb +139 -0
- data/lib/acts_as_ordered_tree/node/traversals.rb +53 -0
- data/lib/acts_as_ordered_tree/persevering_transaction.rb +93 -0
- data/lib/acts_as_ordered_tree/position.rb +143 -0
- data/lib/acts_as_ordered_tree/relation/arrangeable.rb +33 -0
- data/lib/acts_as_ordered_tree/relation/iterable.rb +41 -0
- data/lib/acts_as_ordered_tree/relation/preloaded.rb +46 -11
- data/lib/acts_as_ordered_tree/transaction/base.rb +57 -0
- data/lib/acts_as_ordered_tree/transaction/callbacks.rb +67 -0
- data/lib/acts_as_ordered_tree/transaction/create.rb +68 -0
- data/lib/acts_as_ordered_tree/transaction/destroy.rb +34 -0
- data/lib/acts_as_ordered_tree/transaction/dsl.rb +214 -0
- data/lib/acts_as_ordered_tree/transaction/factory.rb +67 -0
- data/lib/acts_as_ordered_tree/transaction/move.rb +70 -0
- data/lib/acts_as_ordered_tree/transaction/passthrough.rb +12 -0
- data/lib/acts_as_ordered_tree/transaction/reorder.rb +42 -0
- data/lib/acts_as_ordered_tree/transaction/save.rb +64 -0
- data/lib/acts_as_ordered_tree/transaction/update.rb +78 -0
- data/lib/acts_as_ordered_tree/tree.rb +148 -0
- data/lib/acts_as_ordered_tree/tree/association.rb +20 -0
- data/lib/acts_as_ordered_tree/tree/callbacks.rb +57 -0
- data/lib/acts_as_ordered_tree/tree/children_association.rb +120 -0
- data/lib/acts_as_ordered_tree/tree/columns.rb +102 -0
- data/lib/acts_as_ordered_tree/tree/deprecated_columns_accessors.rb +24 -0
- data/lib/acts_as_ordered_tree/tree/parent_association.rb +31 -0
- data/lib/acts_as_ordered_tree/tree/perseverance.rb +19 -0
- data/lib/acts_as_ordered_tree/tree/scopes.rb +56 -0
- data/lib/acts_as_ordered_tree/validators.rb +1 -1
- data/lib/acts_as_ordered_tree/version.rb +1 -1
- data/spec/acts_as_ordered_tree_spec.rb +80 -909
- data/spec/adapters/postgresql_spec.rb +14 -0
- data/spec/adapters/recursive_spec.rb +12 -0
- data/spec/adapters/shared.rb +272 -0
- data/spec/callbacks_spec.rb +177 -0
- data/spec/counter_cache_spec.rb +31 -0
- data/spec/create_spec.rb +110 -0
- data/spec/destroy_spec.rb +57 -0
- data/spec/inheritance_spec.rb +176 -0
- data/spec/move_spec.rb +94 -0
- data/spec/node/movements/concurrent_movements_spec.rb +354 -0
- data/spec/node/movements/move_higher_spec.rb +46 -0
- data/spec/node/movements/move_lower_spec.rb +46 -0
- data/spec/node/movements/move_to_child_of_spec.rb +147 -0
- data/spec/node/movements/move_to_child_with_index_spec.rb +124 -0
- data/spec/node/movements/move_to_child_with_position_spec.rb +85 -0
- data/spec/node/movements/move_to_left_of_spec.rb +120 -0
- data/spec/node/movements/move_to_right_of_spec.rb +120 -0
- data/spec/node/movements/move_to_root_spec.rb +67 -0
- data/spec/node/predicates_spec.rb +211 -0
- data/spec/node/reloading_spec.rb +42 -0
- data/spec/node/siblings_spec.rb +193 -0
- data/spec/node/traversals_spec.rb +71 -0
- data/spec/persevering_transaction_spec.rb +98 -0
- data/spec/relation/arrangeable_spec.rb +88 -0
- data/spec/relation/iterable_spec.rb +104 -0
- data/spec/relation/preloaded_spec.rb +57 -0
- data/spec/reorder_spec.rb +83 -0
- data/spec/spec_helper.rb +30 -38
- data/spec/support/db/boot.rb +22 -0
- data/spec/{db → support/db}/config.travis.yml +2 -0
- data/spec/{db → support/db}/config.yml +1 -0
- data/spec/{db → support/db}/schema.rb +9 -0
- data/spec/support/factories.rb +2 -2
- data/spec/support/matchers.rb +67 -58
- data/spec/support/models.rb +6 -14
- data/spec/support/tree_factory.rb +315 -0
- data/spec/tree/children_association_spec.rb +72 -0
- data/spec/tree/columns_spec.rb +65 -0
- data/spec/tree/scopes_spec.rb +39 -0
- metadata +161 -43
- data/lib/acts_as_ordered_tree/adapters/postgresql_adapter.rb +0 -104
- data/lib/acts_as_ordered_tree/arrangeable.rb +0 -80
- data/lib/acts_as_ordered_tree/class_methods.rb +0 -72
- data/lib/acts_as_ordered_tree/relation/base.rb +0 -26
- data/lib/acts_as_ordered_tree/tenacious_transaction.rb +0 -30
- data/spec/concurrency_support_spec.rb +0 -156
@@ -0,0 +1,20 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module ActsAsOrderedTree
|
4
|
+
class Tree
|
5
|
+
class Association
|
6
|
+
attr_reader :tree
|
7
|
+
|
8
|
+
delegate :klass, :to => :tree
|
9
|
+
|
10
|
+
def initialize(tree)
|
11
|
+
@tree = tree
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
def class_name
|
16
|
+
"::#{tree.base_class.name}"
|
17
|
+
end
|
18
|
+
end # class Association
|
19
|
+
end # class Tree
|
20
|
+
end # module ActsAsOrderedTree
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'active_support/core_ext/hash/slice'
|
4
|
+
|
5
|
+
module ActsAsOrderedTree
|
6
|
+
class Tree
|
7
|
+
# Tree callbacks storage
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# MyModel.ordered_tree.callbacks.before_add(parent, child)
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
class Callbacks
|
14
|
+
VALID_KEYS = :before_add,
|
15
|
+
:after_add,
|
16
|
+
:before_remove,
|
17
|
+
:after_remove
|
18
|
+
|
19
|
+
def initialize(klass, options)
|
20
|
+
@klass = klass
|
21
|
+
@callbacks = {}
|
22
|
+
|
23
|
+
options.slice(*VALID_KEYS).each do |k, v|
|
24
|
+
@callbacks[k] = v if v
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# generate accessors and predicates
|
29
|
+
VALID_KEYS.each do |method|
|
30
|
+
define_method(method) do |parent, record| # def before_add(parent, record)
|
31
|
+
run_callbacks(method, parent, record)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def run_callbacks(method, parent, record)
|
37
|
+
callback = callback_for(method)
|
38
|
+
|
39
|
+
case callback
|
40
|
+
when Symbol
|
41
|
+
parent.send(callback, record)
|
42
|
+
when Proc
|
43
|
+
callback.call(parent, record)
|
44
|
+
when nil, false
|
45
|
+
# do nothing
|
46
|
+
else
|
47
|
+
# parent.before_add(record)
|
48
|
+
callback.send(method, parent, record)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def callback_for(method)
|
53
|
+
@callbacks[method]
|
54
|
+
end
|
55
|
+
end # class Callbacks
|
56
|
+
end # class Tree
|
57
|
+
end # module ActsAsOrderedTree
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'acts_as_ordered_tree/compatibility'
|
4
|
+
require 'acts_as_ordered_tree/tree/association'
|
5
|
+
require 'acts_as_ordered_tree/relation/iterable'
|
6
|
+
|
7
|
+
module ActsAsOrderedTree
|
8
|
+
class Tree
|
9
|
+
# @api private
|
10
|
+
class ChildrenAssociation < Association
|
11
|
+
# CounterCache extensions will allow to use cached value
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
module CounterCache
|
15
|
+
def size
|
16
|
+
ordered_tree_node.parent_id_changed? ? super : ordered_tree_node.counter_cache
|
17
|
+
end
|
18
|
+
|
19
|
+
def empty?
|
20
|
+
size == 0
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def ordered_tree_node
|
25
|
+
@association.owner.ordered_tree_node
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Builds association object
|
30
|
+
def build
|
31
|
+
Compatibility.version '< 4.0.0' do
|
32
|
+
opts = options.merge(:conditions => conditions, :order => order)
|
33
|
+
|
34
|
+
klass.has_many(:children, opts)
|
35
|
+
end
|
36
|
+
|
37
|
+
Compatibility.version '>= 4.0.0' do
|
38
|
+
klass.has_many(:children, scope, options)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def options
|
44
|
+
Hash[
|
45
|
+
:class_name => class_name,
|
46
|
+
:foreign_key => tree.columns.parent,
|
47
|
+
:inverse_of => inverse_of,
|
48
|
+
:dependent => :destroy,
|
49
|
+
:extend => [extension, Relation::Iterable].compact
|
50
|
+
]
|
51
|
+
end
|
52
|
+
|
53
|
+
def inverse_of
|
54
|
+
:parent unless tree.options[:polymorphic]
|
55
|
+
end
|
56
|
+
|
57
|
+
# rails 4.x scope for has_many association
|
58
|
+
def scope
|
59
|
+
assoc_scope = method(:association_scope)
|
60
|
+
join_scope = method(:join_association_scope)
|
61
|
+
|
62
|
+
->(join_or_parent) {
|
63
|
+
if join_or_parent.is_a?(ActiveRecord::Associations::JoinDependency::JoinAssociation)
|
64
|
+
join_scope[join_or_parent]
|
65
|
+
elsif join_or_parent.is_a?(ActiveRecord::Base)
|
66
|
+
assoc_scope[join_or_parent]
|
67
|
+
else
|
68
|
+
where(nil)
|
69
|
+
end.extending(Relation::Iterable)
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
# Rails 3.x :conditions options for has_many association
|
74
|
+
def conditions
|
75
|
+
return nil unless tree.columns.scope?
|
76
|
+
|
77
|
+
assoc_scope = method(:association_scope)
|
78
|
+
join_scope = method(:join_association_scope)
|
79
|
+
|
80
|
+
Proc.new do |join_association|
|
81
|
+
conditions = if join_association.is_a?(ActiveRecord::Associations::JoinDependency::JoinAssociation)
|
82
|
+
join_scope[join_association]
|
83
|
+
elsif self.is_a?(ActiveRecord::Base)
|
84
|
+
assoc_scope[self]
|
85
|
+
else
|
86
|
+
where(nil)
|
87
|
+
end.where_values.reduce(:and)
|
88
|
+
|
89
|
+
conditions.try(:to_sql)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def order
|
94
|
+
tree.columns.position
|
95
|
+
end
|
96
|
+
|
97
|
+
def extension
|
98
|
+
if tree.columns.counter_cache?
|
99
|
+
CounterCache
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def join_association_scope(join_association)
|
104
|
+
parent = join_association.respond_to?(:parent) ?
|
105
|
+
join_association.parent.table :
|
106
|
+
join_association.base_klass.arel_table
|
107
|
+
|
108
|
+
child = join_association.table
|
109
|
+
|
110
|
+
conditions = tree.columns.scope.map { |column| parent[column].eq child[column] }.reduce(:and)
|
111
|
+
|
112
|
+
klass.unscoped.where(conditions)
|
113
|
+
end
|
114
|
+
|
115
|
+
def association_scope(owner)
|
116
|
+
owner.ordered_tree_node.scope.order(tree.columns.position)
|
117
|
+
end
|
118
|
+
end # class ChildrenAssociation
|
119
|
+
end # class Tree
|
120
|
+
end # module ActsAsOrderedTree
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module ActsAsOrderedTree
|
4
|
+
class Tree
|
5
|
+
# Ordered tree columns store
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# MyModel.tree.columns.parent # => "parent_id"
|
9
|
+
# MyModel.tree.columns.counter_cache # => nil
|
10
|
+
# MyModel.tree.columns.counter_cache? # => false
|
11
|
+
class Columns
|
12
|
+
# This error is raised when unknown column given in :scope option
|
13
|
+
UnknownColumn = Class.new(StandardError)
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
def self.column_accessor(*names)
|
17
|
+
names.each do |name|
|
18
|
+
define_method "#{name}=" do |value|
|
19
|
+
@columns[name] = value.to_s if column_exists?(value)
|
20
|
+
end
|
21
|
+
private "#{name}=".to_sym
|
22
|
+
|
23
|
+
define_method "#{name}?" do
|
24
|
+
@columns[name].present?
|
25
|
+
end
|
26
|
+
|
27
|
+
define_method name do
|
28
|
+
@columns[name]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# @!method parent
|
34
|
+
# @!method parent?
|
35
|
+
# @!method parent=(value)
|
36
|
+
# @!method position
|
37
|
+
# @!method position?
|
38
|
+
# @!method position=(value)
|
39
|
+
# @!method depth
|
40
|
+
# @!method depth?
|
41
|
+
# @!method depth=(value)
|
42
|
+
# @!method counter_cache
|
43
|
+
# @!method counter_cache?
|
44
|
+
# @!method counter_cache=(value)
|
45
|
+
# @!method scope
|
46
|
+
# @!method scope?
|
47
|
+
column_accessor :parent,
|
48
|
+
:position,
|
49
|
+
:depth,
|
50
|
+
:counter_cache,
|
51
|
+
:scope
|
52
|
+
|
53
|
+
def initialize(klass, options = {})
|
54
|
+
@klass = klass
|
55
|
+
@columns = { :id => id }
|
56
|
+
|
57
|
+
self.parent = options[:parent_column]
|
58
|
+
self.position = options[:position_column]
|
59
|
+
self.depth = options[:depth_column]
|
60
|
+
self.counter_cache = counter_cache_name(options[:counter_cache])
|
61
|
+
self.scope = options[:scope]
|
62
|
+
end
|
63
|
+
|
64
|
+
def [](name)
|
65
|
+
@columns[name]
|
66
|
+
end
|
67
|
+
|
68
|
+
def id
|
69
|
+
@klass.primary_key
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns array of columns names associated with ordered tree structure
|
73
|
+
def to_a
|
74
|
+
@columns.values.flatten.compact
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
undef_method :scope=
|
79
|
+
def scope=(value)
|
80
|
+
columns = Array.wrap(value)
|
81
|
+
|
82
|
+
unknown = columns.reject { |name| column_exists?(name) }
|
83
|
+
|
84
|
+
raise UnknownColumn, "Unknown column#{'s' if unknown.size > 1} passed to :scope option: #{unknown.join(', ')}" if unknown.any?
|
85
|
+
|
86
|
+
@columns[:scope] = columns.map(&:to_s)
|
87
|
+
end
|
88
|
+
|
89
|
+
def counter_cache_name(value)
|
90
|
+
if value == true
|
91
|
+
"#{@klass.name.demodulize.underscore.pluralize}_count"
|
92
|
+
else
|
93
|
+
value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def column_exists?(name)
|
98
|
+
name.present? && @klass.columns_hash.include?(name.to_s)
|
99
|
+
end
|
100
|
+
end # class Columns
|
101
|
+
end # class Tree
|
102
|
+
end # module ActsAsOrderedTree
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ActsAsOrderedTree
|
2
|
+
class Tree
|
3
|
+
# @deprecated Use `ordered_tree.columns` object
|
4
|
+
module DeprecatedColumnsAccessors
|
5
|
+
class << self
|
6
|
+
# @api private
|
7
|
+
def deprecated_method(method, delegate)
|
8
|
+
define_method(method) do
|
9
|
+
ActiveSupport::Deprecation.warn("#{name}.#{method} is deprecated in favor of #{name}.ordered_tree.columns.#{delegate}", caller(1))
|
10
|
+
|
11
|
+
ordered_tree.columns.send(delegate)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
private :deprecated_method
|
15
|
+
end
|
16
|
+
|
17
|
+
deprecated_method :parent_column, :parent
|
18
|
+
deprecated_method :position_column, :position
|
19
|
+
deprecated_method :depth_column, :depth
|
20
|
+
deprecated_method :children_counter_cache_column, :counter_cache
|
21
|
+
deprecated_method :scope_column_name, :scope
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'acts_as_ordered_tree/tree/association'
|
4
|
+
|
5
|
+
module ActsAsOrderedTree
|
6
|
+
class Tree
|
7
|
+
class ParentAssociation < Association
|
8
|
+
# create parent association
|
9
|
+
#
|
10
|
+
# we cannot use native :counter_cache callbacks because they suck! :(
|
11
|
+
# they act like this:
|
12
|
+
# node.parent = new_parent # and here counters are updated, outside of transaction!
|
13
|
+
def build
|
14
|
+
klass.belongs_to(:parent, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def options
|
19
|
+
Hash[
|
20
|
+
:class_name => class_name,
|
21
|
+
:foreign_key => tree.columns.parent,
|
22
|
+
:inverse_of => inverse_of
|
23
|
+
]
|
24
|
+
end
|
25
|
+
|
26
|
+
def inverse_of
|
27
|
+
:children unless tree.options[:polymorphic]
|
28
|
+
end
|
29
|
+
end # class ParentAssociation
|
30
|
+
end # class Tree
|
31
|
+
end # module ActsAsOrderedTree
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'acts_as_ordered_tree/persevering_transaction'
|
4
|
+
|
5
|
+
module ActsAsOrderedTree
|
6
|
+
class Tree
|
7
|
+
# This module contains overridden :with_transaction_returning_status method
|
8
|
+
# which wraps itself into PerseveringTransaction.
|
9
|
+
#
|
10
|
+
# This module is mixed in into Class after Class.acts_as_ordered_tree invocation.
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
module Perseverance
|
14
|
+
def with_transaction_returning_status
|
15
|
+
PerseveringTransaction.new(self.class.connection).start { super }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module ActsAsOrderedTree
|
4
|
+
class Tree
|
5
|
+
module Scopes
|
6
|
+
# Returns nodes ordered by their position.
|
7
|
+
#
|
8
|
+
# @return [ActiveRecord::Relation]
|
9
|
+
def preorder
|
10
|
+
order arel_table[ordered_tree.columns.position].asc
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns all nodes that don't have parent.
|
14
|
+
#
|
15
|
+
# @return [ActiveRecord::Relation]
|
16
|
+
def roots
|
17
|
+
preorder.where arel_table[ordered_tree.columns.parent].eq nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns all nodes that do not have any children. May be quite inefficient.
|
21
|
+
#
|
22
|
+
# @return [ActiveRecord::Relation]
|
23
|
+
def root
|
24
|
+
roots.first
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns all nodes that do not have any children. May be quite inefficient.
|
28
|
+
#
|
29
|
+
# @return [ActiveRecord::Relation]
|
30
|
+
def leaves
|
31
|
+
if ordered_tree.columns.counter_cache?
|
32
|
+
leaves_with_counter_cache
|
33
|
+
else
|
34
|
+
leaves_without_counter_cache
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def leaves_without_counter_cache
|
40
|
+
aliaz = Arel::Nodes::TableAlias.new(arel_table, 't')
|
41
|
+
|
42
|
+
subquery = unscoped.select('1').
|
43
|
+
from(aliaz).
|
44
|
+
where(aliaz[ordered_tree.columns.parent].eq(arel_table[primary_key])).
|
45
|
+
limit(1).
|
46
|
+
reorder(nil)
|
47
|
+
|
48
|
+
where "NOT EXISTS (#{subquery.to_sql})"
|
49
|
+
end
|
50
|
+
|
51
|
+
def leaves_with_counter_cache
|
52
|
+
where arel_table[ordered_tree.columns.counter_cache].eq 0
|
53
|
+
end
|
54
|
+
end # module Scopes
|
55
|
+
end # class Tree
|
56
|
+
end # module ActsAsOrderedTree
|
@@ -8,7 +8,7 @@ module ActsAsOrderedTree
|
|
8
8
|
|
9
9
|
class ScopeValidator < ActiveModel::Validator
|
10
10
|
def validate(record)
|
11
|
-
record.errors.add(:parent, :scope) unless record.same_scope?(record.parent)
|
11
|
+
record.errors.add(:parent, :scope) unless record.ordered_tree_node.same_scope?(record.parent)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|