acts_as_list 0.9.17 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/FUNDING.yml +3 -0
- data/.travis.yml +11 -40
- data/Appraisals +15 -31
- data/CHANGELOG.md +411 -348
- data/Gemfile +6 -5
- data/README.md +105 -7
- data/Rakefile +1 -1
- data/acts_as_list.gemspec +15 -10
- data/gemfiles/rails_4_2.gemfile +5 -6
- data/gemfiles/rails_5_0.gemfile +4 -6
- data/gemfiles/rails_5_1.gemfile +4 -6
- data/gemfiles/rails_5_2.gemfile +4 -6
- data/gemfiles/{rails_4_1.gemfile → rails_6_0.gemfile} +4 -7
- data/lib/acts_as_list/active_record/acts/list.rb +54 -60
- data/lib/acts_as_list/active_record/acts/no_update.rb +14 -4
- data/lib/acts_as_list/active_record/acts/position_column_method_definer.rb +18 -5
- data/lib/acts_as_list/active_record/acts/scope_method_definer.rb +7 -5
- data/lib/acts_as_list/active_record/acts/sequential_updates_method_definer.rb +1 -1
- data/lib/acts_as_list/version.rb +1 -1
- data/test/helper.rb +1 -10
- data/test/shared_list.rb +8 -4
- data/test/shared_list_sub.rb +1 -1
- data/test/test_list.rb +192 -57
- data/test/test_no_update_for_extra_classes.rb +30 -5
- data/test/test_no_update_for_scope_destruction.rb +2 -7
- data/test/test_no_update_for_subclasses.rb +3 -3
- data/test/test_scope_with_user_defined_foreign_key.rb +42 -0
- metadata +17 -13
- data/gemfiles/rails_3_2.gemfile +0 -34
@@ -89,20 +89,30 @@ module ActiveRecord
|
|
89
89
|
|
90
90
|
class << self
|
91
91
|
def apply_to(klasses)
|
92
|
-
|
92
|
+
klasses.map {|klass| add_klass(klass)}
|
93
93
|
yield
|
94
94
|
ensure
|
95
|
-
|
95
|
+
klasses.map {|klass| remove_klass(klass)}
|
96
96
|
end
|
97
97
|
|
98
98
|
def applied_to?(klass)
|
99
|
-
!(klass.ancestors & extracted_klasses).empty?
|
99
|
+
!(klass.ancestors & extracted_klasses.keys).empty?
|
100
100
|
end
|
101
101
|
|
102
102
|
private
|
103
103
|
|
104
104
|
def extracted_klasses
|
105
|
-
Thread.current[:act_as_list_no_update] ||=
|
105
|
+
Thread.current[:act_as_list_no_update] ||= {}
|
106
|
+
end
|
107
|
+
|
108
|
+
def add_klass(klass)
|
109
|
+
extracted_klasses[klass] = 0 unless extracted_klasses.key?(klass)
|
110
|
+
extracted_klasses[klass] += 1
|
111
|
+
end
|
112
|
+
|
113
|
+
def remove_klass(klass)
|
114
|
+
extracted_klasses[klass] -= 1
|
115
|
+
extracted_klasses.delete(klass) if extracted_klasses[klass] <= 0
|
106
116
|
end
|
107
117
|
end
|
108
118
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord::Acts::List::PositionColumnMethodDefiner #:nodoc:
|
4
|
-
def self.call(caller_class, position_column)
|
5
|
-
define_class_methods(caller_class, position_column)
|
4
|
+
def self.call(caller_class, position_column, touch_on_update)
|
5
|
+
define_class_methods(caller_class, position_column, touch_on_update)
|
6
6
|
define_instance_methods(caller_class, position_column)
|
7
7
|
|
8
8
|
if mass_assignment_protection_was_used_by_user?(caller_class)
|
@@ -12,7 +12,7 @@ module ActiveRecord::Acts::List::PositionColumnMethodDefiner #:nodoc:
|
|
12
12
|
|
13
13
|
private
|
14
14
|
|
15
|
-
def self.define_class_methods(caller_class, position_column)
|
15
|
+
def self.define_class_methods(caller_class, position_column, touch_on_update)
|
16
16
|
caller_class.class_eval do
|
17
17
|
define_singleton_method :quoted_position_column do
|
18
18
|
@_quoted_position_column ||= connection.quote_column_name(position_column)
|
@@ -22,6 +22,18 @@ module ActiveRecord::Acts::List::PositionColumnMethodDefiner #:nodoc:
|
|
22
22
|
@_quoted_position_column_with_table_name ||= "#{caller_class.quoted_table_name}.#{quoted_position_column}"
|
23
23
|
end
|
24
24
|
|
25
|
+
define_singleton_method :decrement_sequentially do
|
26
|
+
pluck(primary_key).each do |id|
|
27
|
+
where(primary_key => id).decrement_all
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
define_singleton_method :increment_sequentially do
|
32
|
+
pluck(primary_key).each do |id|
|
33
|
+
where(primary_key => id).increment_all
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
25
37
|
define_singleton_method :decrement_all do
|
26
38
|
update_all_with_touch "#{quoted_position_column} = (#{quoted_position_column_with_table_name} - 1)"
|
27
39
|
end
|
@@ -31,7 +43,8 @@ module ActiveRecord::Acts::List::PositionColumnMethodDefiner #:nodoc:
|
|
31
43
|
end
|
32
44
|
|
33
45
|
define_singleton_method :update_all_with_touch do |updates|
|
34
|
-
|
46
|
+
updates += touch_record_sql if touch_on_update
|
47
|
+
update_all(updates)
|
35
48
|
end
|
36
49
|
|
37
50
|
private
|
@@ -51,7 +64,7 @@ module ActiveRecord::Acts::List::PositionColumnMethodDefiner #:nodoc:
|
|
51
64
|
end
|
52
65
|
|
53
66
|
define_method :"#{position_column}=" do |position|
|
54
|
-
|
67
|
+
self[position_column] = position
|
55
68
|
@position_changed = true
|
56
69
|
end
|
57
70
|
|
@@ -4,7 +4,7 @@ module ActiveRecord::Acts::List::ScopeMethodDefiner #:nodoc:
|
|
4
4
|
extend ActiveSupport::Inflector
|
5
5
|
|
6
6
|
def self.call(caller_class, scope)
|
7
|
-
scope = idify(scope) if scope.is_a?(Symbol)
|
7
|
+
scope = idify(caller_class, scope) if scope.is_a?(Symbol)
|
8
8
|
|
9
9
|
caller_class.class_eval do
|
10
10
|
define_method :scope_name do
|
@@ -21,7 +21,6 @@ module ActiveRecord::Acts::List::ScopeMethodDefiner #:nodoc:
|
|
21
21
|
end
|
22
22
|
|
23
23
|
define_method :destroyed_via_scope? do
|
24
|
-
return false if ActiveRecord::VERSION::MAJOR < 4
|
25
24
|
scope == (destroyed_by_association && destroyed_by_association.foreign_key.to_sym)
|
26
25
|
end
|
27
26
|
elsif scope.is_a?(Array)
|
@@ -45,7 +44,6 @@ module ActiveRecord::Acts::List::ScopeMethodDefiner #:nodoc:
|
|
45
44
|
end
|
46
45
|
|
47
46
|
define_method :destroyed_via_scope? do
|
48
|
-
return false if ActiveRecord::VERSION::MAJOR < 4
|
49
47
|
scope_condition.keys.include? (destroyed_by_association && destroyed_by_association.foreign_key.to_sym)
|
50
48
|
end
|
51
49
|
else
|
@@ -66,9 +64,13 @@ module ActiveRecord::Acts::List::ScopeMethodDefiner #:nodoc:
|
|
66
64
|
end
|
67
65
|
end
|
68
66
|
|
69
|
-
def self.idify(name)
|
67
|
+
def self.idify(caller_class, name)
|
70
68
|
return name if name.to_s =~ /_id$/
|
71
69
|
|
72
|
-
|
70
|
+
if caller_class.reflections.key?(name.to_s)
|
71
|
+
caller_class.reflections[name.to_s].foreign_key.to_sym
|
72
|
+
else
|
73
|
+
foreign_key(name).to_sym
|
74
|
+
end
|
73
75
|
end
|
74
76
|
end
|
@@ -7,7 +7,7 @@ module ActiveRecord::Acts::List::SequentialUpdatesMethodDefiner #:nodoc:
|
|
7
7
|
if !defined?(@sequential_updates)
|
8
8
|
if sequential_updates_option.nil?
|
9
9
|
table_exists =
|
10
|
-
if
|
10
|
+
if active_record_version_is?('>= 5')
|
11
11
|
caller_class.connection.data_source_exists?(caller_class.table_name)
|
12
12
|
else
|
13
13
|
caller_class.connection.table_exists?(caller_class.table_name)
|
data/lib/acts_as_list/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -13,7 +13,7 @@ rescue Bundler::BundlerError => e
|
|
13
13
|
end
|
14
14
|
require "active_record"
|
15
15
|
require "minitest/autorun"
|
16
|
-
require "mocha/
|
16
|
+
require "mocha/minitest"
|
17
17
|
require "#{File.dirname(__FILE__)}/../init"
|
18
18
|
|
19
19
|
if defined?(ActiveRecord::VERSION) &&
|
@@ -27,15 +27,6 @@ db_config = YAML.load_file(File.expand_path("../database.yml", __FILE__)).fetch(
|
|
27
27
|
ActiveRecord::Base.establish_connection(db_config)
|
28
28
|
ActiveRecord::Schema.verbose = false
|
29
29
|
|
30
|
-
# Returns true if ActiveRecord is rails 3, 4 version
|
31
|
-
def rails_3
|
32
|
-
defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::MAJOR >= 3
|
33
|
-
end
|
34
|
-
|
35
|
-
def rails_4
|
36
|
-
defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::MAJOR >= 4
|
37
|
-
end
|
38
|
-
|
39
30
|
def teardown_db
|
40
31
|
if ActiveRecord::VERSION::MAJOR >= 5
|
41
32
|
tables = ActiveRecord::Base.connection.data_sources
|
data/test/shared_list.rb
CHANGED
@@ -10,6 +10,13 @@ module Shared
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
def test_current_position
|
14
|
+
first_item = ListMixin.where(parent_id: 5).first
|
15
|
+
assert_equal 1, first_item.current_position
|
16
|
+
first_item.remove_from_list
|
17
|
+
assert_nil first_item.current_position
|
18
|
+
end
|
19
|
+
|
13
20
|
def test_reordering
|
14
21
|
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
|
15
22
|
|
@@ -230,12 +237,9 @@ module Shared
|
|
230
237
|
# We need to trigger all the before_destroy callbacks without actually
|
231
238
|
# destroying the record so we can see the affect the callbacks have on
|
232
239
|
# the record.
|
233
|
-
# NOTE: Hotfix for rails3 ActiveRecord
|
234
240
|
list = ListMixin.where(id: 2).first
|
235
241
|
if list.respond_to?(:run_callbacks)
|
236
|
-
|
237
|
-
list.run_callbacks(:destroy) if rails_3
|
238
|
-
list.run_callbacks(:before_destroy) if !rails_3
|
242
|
+
list.run_callbacks(:destroy)
|
239
243
|
else
|
240
244
|
list.send(:callback, :before_destroy)
|
241
245
|
end
|
data/test/shared_list_sub.rb
CHANGED
@@ -47,7 +47,7 @@ module Shared
|
|
47
47
|
|
48
48
|
def test_next_prev_not_regular_sequence
|
49
49
|
ListMixin.all.each do |item|
|
50
|
-
item.
|
50
|
+
item.update pos: item.pos * 5
|
51
51
|
end
|
52
52
|
|
53
53
|
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
|
data/test/test_list.rb
CHANGED
@@ -39,11 +39,18 @@ def setup_db(position_options = {})
|
|
39
39
|
t.column :order, :integer
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
# This table is used to test table names with different primary_key columns
|
43
|
+
ActiveRecord::Base.connection.create_table 'altid-table', primary_key: 'altid' do |t|
|
44
|
+
t.column :pos, :integer
|
45
|
+
t.column :created_at, :datetime
|
46
|
+
t.column :updated_at, :datetime
|
47
|
+
end
|
45
48
|
|
46
|
-
|
49
|
+
ActiveRecord::Base.connection.add_index 'altid-table', :pos, unique: true
|
50
|
+
|
51
|
+
mixins = [ Mixin, ListMixin, ListMixinSub1, ListMixinSub2, ListWithStringScopeMixin,
|
52
|
+
ArrayScopeListMixin, ZeroBasedMixin, DefaultScopedMixin, EnumArrayScopeListMixin,
|
53
|
+
DefaultScopedWhereMixin, TopAdditionMixin, NoAdditionMixin, QuotedList, TouchDisabledMixin ]
|
47
54
|
|
48
55
|
ActiveRecord::Base.connection.schema_cache.clear!
|
49
56
|
mixins.each do |klass|
|
@@ -63,23 +70,19 @@ class ListMixin < Mixin
|
|
63
70
|
acts_as_list column: "pos", scope: :parent
|
64
71
|
end
|
65
72
|
|
73
|
+
class TouchDisabledMixin < Mixin
|
74
|
+
acts_as_list column: "pos", touch_on_update: false
|
75
|
+
end
|
76
|
+
|
66
77
|
class ListMixinSub1 < ListMixin
|
67
78
|
end
|
68
79
|
|
69
80
|
class ListMixinSub2 < ListMixin
|
70
|
-
|
71
|
-
validates :pos, presence: true
|
72
|
-
else
|
73
|
-
validates_presence_of :pos
|
74
|
-
end
|
81
|
+
validates :pos, presence: true
|
75
82
|
end
|
76
83
|
|
77
84
|
class ListMixinError < ListMixin
|
78
|
-
|
79
|
-
validates :state, presence: true
|
80
|
-
else
|
81
|
-
validates_presence_of :state
|
82
|
-
end
|
85
|
+
validates :state, presence: true
|
83
86
|
end
|
84
87
|
|
85
88
|
class ListWithStringScopeMixin < Mixin
|
@@ -94,13 +97,11 @@ class ArrayScopeListWithHashMixin < Mixin
|
|
94
97
|
acts_as_list column: "pos", scope: [:parent_id, state: nil]
|
95
98
|
end
|
96
99
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
enum state: STATE_VALUES
|
100
|
+
class EnumArrayScopeListMixin < Mixin
|
101
|
+
STATE_VALUES = %w(active archived)
|
102
|
+
enum state: STATE_VALUES
|
101
103
|
|
102
|
-
|
103
|
-
end
|
104
|
+
acts_as_list column: "pos", scope: [:parent_id, :state]
|
104
105
|
end
|
105
106
|
|
106
107
|
class ZeroBasedMixin < Mixin
|
@@ -117,13 +118,7 @@ class DefaultScopedWhereMixin < Mixin
|
|
117
118
|
default_scope { order('pos ASC').where(active: true) }
|
118
119
|
|
119
120
|
def self.for_active_false_tests
|
120
|
-
|
121
|
-
unscoped do
|
122
|
-
order('pos ASC').where(active: false)
|
123
|
-
end
|
124
|
-
else
|
125
|
-
unscope(:where).where(active: false)
|
126
|
-
end
|
121
|
+
unscope(:where).where(active: false)
|
127
122
|
end
|
128
123
|
end
|
129
124
|
|
@@ -131,6 +126,17 @@ class SequentialUpdatesDefault < Mixin
|
|
131
126
|
acts_as_list column: "pos"
|
132
127
|
end
|
133
128
|
|
129
|
+
class SequentialUpdatesAltId < ActiveRecord::Base
|
130
|
+
self.table_name = "altid-table"
|
131
|
+
self.primary_key = "altid"
|
132
|
+
|
133
|
+
acts_as_list column: "pos"
|
134
|
+
end
|
135
|
+
|
136
|
+
class SequentialUpdatesAltIdTouchDisabled < SequentialUpdatesAltId
|
137
|
+
acts_as_list column: "pos", touch_on_update: false
|
138
|
+
end
|
139
|
+
|
134
140
|
class SequentialUpdatesFalseMixin < Mixin
|
135
141
|
acts_as_list column: "pos", sequential_updates: false
|
136
142
|
end
|
@@ -146,7 +152,7 @@ end
|
|
146
152
|
##
|
147
153
|
# The way we track changes to
|
148
154
|
# scope and position can get tripped up
|
149
|
-
# by someone using
|
155
|
+
# by someone using update within
|
150
156
|
# a callback because it causes multiple passes
|
151
157
|
# through the callback chain
|
152
158
|
module CallbackMixin
|
@@ -161,7 +167,7 @@ module CallbackMixin
|
|
161
167
|
# doesn't matter what column changes, just
|
162
168
|
# need to change something
|
163
169
|
|
164
|
-
self.
|
170
|
+
self.update active: !self.active
|
165
171
|
end
|
166
172
|
end
|
167
173
|
end
|
@@ -625,7 +631,7 @@ class MultipleListsTest < ActsAsListTestCase
|
|
625
631
|
def test_check_scope_order
|
626
632
|
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 1).order('pos').map(&:id)
|
627
633
|
assert_equal [5, 6, 7, 8], ListMixin.where(:parent_id => 2).order('pos').map(&:id)
|
628
|
-
ListMixin.find(4).
|
634
|
+
ListMixin.find(4).update :parent_id => 2, :pos => 2
|
629
635
|
assert_equal [1, 2, 3], ListMixin.where(:parent_id => 1).order('pos').map(&:id)
|
630
636
|
assert_equal [5, 4, 6, 7, 8], ListMixin.where(:parent_id => 2).order('pos').map(&:id)
|
631
637
|
end
|
@@ -633,34 +639,32 @@ class MultipleListsTest < ActsAsListTestCase
|
|
633
639
|
def test_check_scope_position
|
634
640
|
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 1).map(&:pos)
|
635
641
|
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 2).map(&:pos)
|
636
|
-
ListMixin.find(4).
|
642
|
+
ListMixin.find(4).update :parent_id => 2, :pos => 2
|
637
643
|
assert_equal [1, 2, 3], ListMixin.where(:parent_id => 1).order('pos').map(&:pos)
|
638
644
|
assert_equal [1, 2, 3, 4, 5], ListMixin.where(:parent_id => 2).order('pos').map(&:pos)
|
639
645
|
end
|
640
646
|
end
|
641
647
|
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
end
|
648
|
+
class EnumArrayScopeListMixinTest < ActsAsListTestCase
|
649
|
+
def setup
|
650
|
+
setup_db
|
651
|
+
EnumArrayScopeListMixin.create! :parent_id => 1, :state => EnumArrayScopeListMixin.states['active']
|
652
|
+
EnumArrayScopeListMixin.create! :parent_id => 1, :state => EnumArrayScopeListMixin.states['archived']
|
653
|
+
EnumArrayScopeListMixin.create! :parent_id => 2, :state => EnumArrayScopeListMixin.states["active"]
|
654
|
+
EnumArrayScopeListMixin.create! :parent_id => 2, :state => EnumArrayScopeListMixin.states["archived"]
|
655
|
+
end
|
651
656
|
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
657
|
+
def test_positions
|
658
|
+
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 1, :state => EnumArrayScopeListMixin.states['active']).map(&:pos)
|
659
|
+
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 1, :state => EnumArrayScopeListMixin.states['archived']).map(&:pos)
|
660
|
+
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['active']).map(&:pos)
|
661
|
+
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['archived']).map(&:pos)
|
662
|
+
end
|
658
663
|
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
end
|
664
|
+
def test_update_state
|
665
|
+
active_item = EnumArrayScopeListMixin.find_by(:parent_id => 2, :state => EnumArrayScopeListMixin.states['active'])
|
666
|
+
active_item.update(state: EnumArrayScopeListMixin.states['archived'])
|
667
|
+
assert_equal [1, 2], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['archived']).map(&:pos).sort
|
664
668
|
end
|
665
669
|
end
|
666
670
|
|
@@ -675,7 +679,7 @@ class MultipleListsArrayScopeTest < ActsAsListTestCase
|
|
675
679
|
def test_order_after_all_scope_properties_are_changed
|
676
680
|
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:id)
|
677
681
|
assert_equal [5, 6, 7, 8], ArrayScopeListMixin.where(:parent_id => 2, :parent_type => 'something').order('pos').map(&:id)
|
678
|
-
ArrayScopeListMixin.find(2).
|
682
|
+
ArrayScopeListMixin.find(2).update :parent_id => 2, :pos => 2,:parent_type => 'something'
|
679
683
|
assert_equal [1, 3, 4], ArrayScopeListMixin.where(:parent_id => 1,:parent_type => 'anything').order('pos').map(&:id)
|
680
684
|
assert_equal [5, 2, 6, 7, 8], ArrayScopeListMixin.where(:parent_id => 2,:parent_type => 'something').order('pos').map(&:id)
|
681
685
|
end
|
@@ -683,7 +687,7 @@ class MultipleListsArrayScopeTest < ActsAsListTestCase
|
|
683
687
|
def test_position_after_all_scope_properties_are_changed
|
684
688
|
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').map(&:pos)
|
685
689
|
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 2, :parent_type => 'something').map(&:pos)
|
686
|
-
ArrayScopeListMixin.find(4).
|
690
|
+
ArrayScopeListMixin.find(4).update :parent_id => 2, :pos => 2, :parent_type => 'something'
|
687
691
|
assert_equal [1, 2, 3], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:pos)
|
688
692
|
assert_equal [1, 2, 3, 4, 5], ArrayScopeListMixin.where(:parent_id => 2, :parent_type => 'something').order('pos').map(&:pos)
|
689
693
|
end
|
@@ -691,7 +695,7 @@ class MultipleListsArrayScopeTest < ActsAsListTestCase
|
|
691
695
|
def test_order_after_one_scope_property_is_changed
|
692
696
|
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:id)
|
693
697
|
assert_equal [9, 10, 11, 12], ArrayScopeListMixin.where(:parent_id => 3, :parent_type => 'anything').order('pos').map(&:id)
|
694
|
-
ArrayScopeListMixin.find(2).
|
698
|
+
ArrayScopeListMixin.find(2).update :parent_id => 3, :pos => 2
|
695
699
|
assert_equal [1, 3, 4], ArrayScopeListMixin.where(:parent_id => 1,:parent_type => 'anything').order('pos').map(&:id)
|
696
700
|
assert_equal [9, 2, 10, 11, 12], ArrayScopeListMixin.where(:parent_id => 3,:parent_type => 'anything').order('pos').map(&:id)
|
697
701
|
end
|
@@ -699,7 +703,7 @@ class MultipleListsArrayScopeTest < ActsAsListTestCase
|
|
699
703
|
def test_position_after_one_scope_property_is_changed
|
700
704
|
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').map(&:pos)
|
701
705
|
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 3, :parent_type => 'anything').map(&:pos)
|
702
|
-
ArrayScopeListMixin.find(4).
|
706
|
+
ArrayScopeListMixin.find(4).update :parent_id => 3, :pos => 2
|
703
707
|
assert_equal [1, 2, 3], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:pos)
|
704
708
|
assert_equal [1, 2, 3, 4, 5], ArrayScopeListMixin.where(:parent_id => 3, :parent_type => 'anything').order('pos').map(&:pos)
|
705
709
|
end
|
@@ -707,7 +711,7 @@ class MultipleListsArrayScopeTest < ActsAsListTestCase
|
|
707
711
|
def test_order_after_moving_to_empty_list
|
708
712
|
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:id)
|
709
713
|
assert_equal [], ArrayScopeListMixin.where(:parent_id => 4, :parent_type => 'anything').order('pos').map(&:id)
|
710
|
-
ArrayScopeListMixin.find(2).
|
714
|
+
ArrayScopeListMixin.find(2).update :parent_id => 4, :pos => 1
|
711
715
|
assert_equal [1, 3, 4], ArrayScopeListMixin.where(:parent_id => 1,:parent_type => 'anything').order('pos').map(&:id)
|
712
716
|
assert_equal [2], ArrayScopeListMixin.where(:parent_id => 4,:parent_type => 'anything').order('pos').map(&:id)
|
713
717
|
end
|
@@ -715,7 +719,7 @@ class MultipleListsArrayScopeTest < ActsAsListTestCase
|
|
715
719
|
def test_position_after_moving_to_empty_list
|
716
720
|
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').map(&:pos)
|
717
721
|
assert_equal [], ArrayScopeListMixin.where(:parent_id => 4, :parent_type => 'anything').map(&:pos)
|
718
|
-
ArrayScopeListMixin.find(2).
|
722
|
+
ArrayScopeListMixin.find(2).update :parent_id => 4, :pos => 1
|
719
723
|
assert_equal [1, 2, 3], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:pos)
|
720
724
|
assert_equal [1], ArrayScopeListMixin.where(:parent_id => 4, :parent_type => 'anything').order('pos').map(&:pos)
|
721
725
|
end
|
@@ -812,6 +816,41 @@ class TouchTest < ActsAsListTestCase
|
|
812
816
|
end
|
813
817
|
end
|
814
818
|
|
819
|
+
class TouchDisabledTest < ActsAsListTestCase
|
820
|
+
def setup
|
821
|
+
setup_db
|
822
|
+
Timecop.freeze(yesterday) do
|
823
|
+
4.times { TouchDisabledMixin.create! }
|
824
|
+
end
|
825
|
+
end
|
826
|
+
|
827
|
+
def now
|
828
|
+
@now ||= Time.current.change(usec: 0)
|
829
|
+
end
|
830
|
+
|
831
|
+
def yesterday
|
832
|
+
@yesterday ||= 1.day.ago
|
833
|
+
end
|
834
|
+
|
835
|
+
def updated_ats
|
836
|
+
TouchDisabledMixin.order(:id).pluck(:updated_at)
|
837
|
+
end
|
838
|
+
|
839
|
+
def positions
|
840
|
+
ListMixin.order(:id).pluck(:pos)
|
841
|
+
end
|
842
|
+
|
843
|
+
def test_deleting_item_does_not_touch_higher_items
|
844
|
+
Timecop.freeze(now) do
|
845
|
+
TouchDisabledMixin.first.destroy
|
846
|
+
updated_ats.each do |updated_at|
|
847
|
+
assert_equal updated_at.to_i, yesterday.to_i
|
848
|
+
end
|
849
|
+
assert_equal positions, [1, 2, 3]
|
850
|
+
end
|
851
|
+
end
|
852
|
+
end
|
853
|
+
|
815
854
|
class ActsAsListTopTest < ActsAsListTestCase
|
816
855
|
def setup
|
817
856
|
setup_db
|
@@ -930,4 +969,100 @@ class SequentialUpdatesMixinNotNullUniquePositiveConstraintsTest < ActsAsListTes
|
|
930
969
|
new_item.insert_at(0)
|
931
970
|
end
|
932
971
|
end
|
972
|
+
|
973
|
+
|
974
|
+
class SequentialUpdatesMixinNotNullUniquePositiveConstraintsTest < ActsAsListTestCase
|
975
|
+
def setup
|
976
|
+
setup_db null: false, unique: true, positive: true
|
977
|
+
(1..4).each { |counter| SequentialUpdatesAltId.create!({pos: counter}) }
|
978
|
+
end
|
979
|
+
|
980
|
+
def test_sequential_updates_default_to_true_with_unique_index
|
981
|
+
assert_equal true, SequentialUpdatesAltId.new.send(:sequential_updates?)
|
982
|
+
end
|
983
|
+
|
984
|
+
def test_insert_at
|
985
|
+
new = SequentialUpdatesAltId.create
|
986
|
+
assert_equal 5, new.pos
|
987
|
+
|
988
|
+
new.insert_at(1)
|
989
|
+
assert_equal 1, new.pos
|
990
|
+
|
991
|
+
new.insert_at(5)
|
992
|
+
assert_equal 5, new.pos
|
993
|
+
|
994
|
+
new.insert_at(3)
|
995
|
+
assert_equal 3, new.pos
|
996
|
+
end
|
997
|
+
|
998
|
+
def test_create_at_top
|
999
|
+
new = SequentialUpdatesAltId.create!(pos: 1)
|
1000
|
+
assert_equal 1, new.pos
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
def test_move_to_bottom
|
1004
|
+
item = SequentialUpdatesAltId.order(:pos).first
|
1005
|
+
item.move_to_bottom
|
1006
|
+
assert_equal 4, item.pos
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
def test_move_to_top
|
1010
|
+
new_item = SequentialUpdatesAltId.create!
|
1011
|
+
assert_equal 5, new_item.pos
|
1012
|
+
|
1013
|
+
new_item.move_to_top
|
1014
|
+
assert_equal 1, new_item.pos
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
def test_destroy
|
1018
|
+
new_item = SequentialUpdatesAltId.create
|
1019
|
+
assert_equal 5, new_item.pos
|
1020
|
+
|
1021
|
+
new_item.insert_at(2)
|
1022
|
+
assert_equal 2, new_item.pos
|
1023
|
+
|
1024
|
+
new_item.destroy
|
1025
|
+
assert_equal [1,2,3,4], SequentialUpdatesAltId.all.map(&:pos).sort
|
1026
|
+
|
1027
|
+
end
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
class SequentialUpdatesAltIdTouchDisabledTest < ActsAsListTestCase
|
1031
|
+
def setup
|
1032
|
+
setup_db
|
1033
|
+
Timecop.freeze(yesterday) do
|
1034
|
+
4.times { SequentialUpdatesAltIdTouchDisabled.create! }
|
1035
|
+
end
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
def now
|
1039
|
+
@now ||= Time.current.change(usec: 0)
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
def yesterday
|
1043
|
+
@yesterday ||= 1.day.ago
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
def updated_ats
|
1047
|
+
SequentialUpdatesAltIdTouchDisabled.order(:altid).pluck(:updated_at)
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
def positions
|
1051
|
+
SequentialUpdatesAltIdTouchDisabled.order(:altid).pluck(:pos)
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
def test_sequential_updates_default_to_true_with_unique_index
|
1055
|
+
assert_equal true, SequentialUpdatesAltIdTouchDisabled.new.send(:sequential_updates?)
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
def test_deleting_item_does_not_touch_higher_items
|
1059
|
+
Timecop.freeze(now) do
|
1060
|
+
SequentialUpdatesAltIdTouchDisabled.first.destroy
|
1061
|
+
updated_ats.each do |updated_at|
|
1062
|
+
assert_equal updated_at.to_i, yesterday.to_i
|
1063
|
+
end
|
1064
|
+
assert_equal positions, [1, 2, 3]
|
1065
|
+
end
|
1066
|
+
end
|
1067
|
+
end
|
933
1068
|
end
|