acts_as_list 1.0.4 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -4
- data/README.md +17 -9
- data/Rakefile +0 -8
- data/lib/acts_as_list/active_record/acts/callback_definer.rb +2 -4
- data/lib/acts_as_list/active_record/acts/list.rb +33 -34
- data/lib/acts_as_list/active_record/acts/position_column_method_definer.rb +15 -6
- data/lib/acts_as_list/active_record/acts/scope_method_definer.rb +1 -2
- data/lib/acts_as_list/active_record/acts/sequential_updates_method_definer.rb +15 -15
- data/lib/acts_as_list/active_record/acts/with_connection.rb +25 -0
- data/lib/acts_as_list/version.rb +1 -1
- metadata +102 -61
- data/.github/FUNDING.yml +0 -3
- data/.gitignore +0 -12
- data/.travis.yml +0 -55
- data/Appraisals +0 -40
- data/Gemfile +0 -28
- data/acts_as_list.gemspec +0 -34
- data/gemfiles/rails_4_2.gemfile +0 -32
- data/gemfiles/rails_5_0.gemfile +0 -31
- data/gemfiles/rails_5_1.gemfile +0 -31
- data/gemfiles/rails_5_2.gemfile +0 -31
- data/gemfiles/rails_6_0.gemfile +0 -31
- data/gemfiles/rails_6_1.gemfile +0 -31
- data/test/database.yml +0 -16
- data/test/helper.rb +0 -69
- data/test/shared.rb +0 -12
- data/test/shared_array_scope_list.rb +0 -177
- data/test/shared_list.rb +0 -324
- data/test/shared_list_sub.rb +0 -188
- data/test/shared_no_addition.rb +0 -38
- data/test/shared_quoting.rb +0 -23
- data/test/shared_top_addition.rb +0 -110
- data/test/shared_zero_based.rb +0 -104
- data/test/test_default_scope_with_select.rb +0 -33
- data/test/test_joined_list.rb +0 -61
- data/test/test_list.rb +0 -1086
- data/test/test_no_update_for_extra_classes.rb +0 -131
- data/test/test_no_update_for_scope_destruction.rb +0 -69
- data/test/test_no_update_for_subclasses.rb +0 -56
- data/test/test_scope_with_user_defined_foreign_key.rb +0 -42
data/test/test_list.rb
DELETED
@@ -1,1086 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# NOTE: following now done in helper.rb (better Readability)
|
4
|
-
require 'helper'
|
5
|
-
|
6
|
-
def setup_db(position_options = {})
|
7
|
-
$default_position = position_options[:default]
|
8
|
-
|
9
|
-
# sqlite cannot drop/rename/alter columns and add constraints after table creation
|
10
|
-
sqlite = ENV.fetch("DB", "sqlite") == "sqlite"
|
11
|
-
|
12
|
-
# AR caches columns options like defaults etc. Clear them!
|
13
|
-
ActiveRecord::Base.connection.create_table :mixins do |t|
|
14
|
-
t.column :pos, :integer, **position_options unless position_options[:positive] && sqlite
|
15
|
-
t.column :active, :boolean, default: true
|
16
|
-
t.column :parent_id, :integer
|
17
|
-
t.column :parent_type, :string
|
18
|
-
t.column :created_at, :datetime
|
19
|
-
t.column :updated_at, :datetime
|
20
|
-
t.column :state, :integer
|
21
|
-
end
|
22
|
-
|
23
|
-
if position_options[:unique] && !(sqlite && position_options[:positive])
|
24
|
-
ActiveRecord::Base.connection.add_index :mixins, :pos, unique: true
|
25
|
-
end
|
26
|
-
|
27
|
-
if position_options[:positive]
|
28
|
-
if sqlite
|
29
|
-
# SQLite cannot add constraint after table creation, also cannot add unique inside ADD COLUMN
|
30
|
-
ActiveRecord::Base.connection.execute('ALTER TABLE mixins ADD COLUMN pos integer8 NOT NULL CHECK (pos > 0) DEFAULT 1')
|
31
|
-
ActiveRecord::Base.connection.execute('CREATE UNIQUE INDEX index_mixins_on_pos ON mixins(pos)')
|
32
|
-
else
|
33
|
-
ActiveRecord::Base.connection.execute('ALTER TABLE mixins ADD CONSTRAINT pos_check CHECK (pos > 0)')
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# This table is used to test table names and column names quoting
|
38
|
-
ActiveRecord::Base.connection.create_table 'table-name' do |t|
|
39
|
-
t.column :order, :integer
|
40
|
-
end
|
41
|
-
|
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
|
48
|
-
|
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 ]
|
54
|
-
|
55
|
-
ActiveRecord::Base.connection.schema_cache.clear!
|
56
|
-
mixins.each do |klass|
|
57
|
-
klass.reset_column_information
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def setup_db_with_default
|
62
|
-
setup_db default: 0
|
63
|
-
end
|
64
|
-
|
65
|
-
class Mixin < ActiveRecord::Base
|
66
|
-
self.table_name = 'mixins'
|
67
|
-
end
|
68
|
-
|
69
|
-
class ListMixin < Mixin
|
70
|
-
acts_as_list column: "pos", scope: :parent
|
71
|
-
end
|
72
|
-
|
73
|
-
class TouchDisabledMixin < Mixin
|
74
|
-
acts_as_list column: "pos", touch_on_update: false
|
75
|
-
end
|
76
|
-
|
77
|
-
class ListMixinSub1 < ListMixin
|
78
|
-
end
|
79
|
-
|
80
|
-
class ListMixinSub2 < ListMixin
|
81
|
-
validates :pos, presence: true
|
82
|
-
end
|
83
|
-
|
84
|
-
class ListMixinError < ListMixin
|
85
|
-
validates :state, presence: true
|
86
|
-
end
|
87
|
-
|
88
|
-
class ListWithStringScopeMixin < Mixin
|
89
|
-
acts_as_list column: "pos", scope: 'parent_id = #{parent_id}'
|
90
|
-
end
|
91
|
-
|
92
|
-
class ArrayScopeListMixin < Mixin
|
93
|
-
acts_as_list column: "pos", scope: [:parent_id, :parent_type]
|
94
|
-
end
|
95
|
-
|
96
|
-
class ArrayScopeListWithHashMixin < Mixin
|
97
|
-
acts_as_list column: "pos", scope: [:parent_id, state: nil]
|
98
|
-
end
|
99
|
-
|
100
|
-
class EnumArrayScopeListMixin < Mixin
|
101
|
-
STATE_VALUES = %w(active archived)
|
102
|
-
enum state: STATE_VALUES
|
103
|
-
|
104
|
-
acts_as_list column: "pos", scope: [:parent_id, :state]
|
105
|
-
end
|
106
|
-
|
107
|
-
class ZeroBasedMixin < Mixin
|
108
|
-
acts_as_list column: "pos", top_of_list: 0, scope: [:parent_id]
|
109
|
-
end
|
110
|
-
|
111
|
-
class DefaultScopedMixin < Mixin
|
112
|
-
acts_as_list column: "pos"
|
113
|
-
default_scope { order('pos ASC') }
|
114
|
-
end
|
115
|
-
|
116
|
-
class DefaultScopedWhereMixin < Mixin
|
117
|
-
acts_as_list column: "pos"
|
118
|
-
default_scope { order('pos ASC').where(active: true) }
|
119
|
-
|
120
|
-
def self.for_active_false_tests
|
121
|
-
unscope(:where).where(active: false)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
class SequentialUpdatesDefault < Mixin
|
126
|
-
acts_as_list column: "pos"
|
127
|
-
end
|
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
|
-
|
140
|
-
class SequentialUpdatesFalseMixin < Mixin
|
141
|
-
acts_as_list column: "pos", sequential_updates: false
|
142
|
-
end
|
143
|
-
|
144
|
-
class TopAdditionMixin < Mixin
|
145
|
-
acts_as_list column: "pos", add_new_at: :top, scope: :parent_id
|
146
|
-
end
|
147
|
-
|
148
|
-
class NoAdditionMixin < Mixin
|
149
|
-
acts_as_list column: "pos", add_new_at: nil, scope: :parent_id
|
150
|
-
end
|
151
|
-
|
152
|
-
##
|
153
|
-
# The way we track changes to
|
154
|
-
# scope and position can get tripped up
|
155
|
-
# by someone using update within
|
156
|
-
# a callback because it causes multiple passes
|
157
|
-
# through the callback chain
|
158
|
-
module CallbackMixin
|
159
|
-
|
160
|
-
def self.included(base)
|
161
|
-
base.send :include, InstanceMethods
|
162
|
-
base.after_create :change_field
|
163
|
-
end
|
164
|
-
|
165
|
-
module InstanceMethods
|
166
|
-
def change_field
|
167
|
-
# doesn't matter what column changes, just
|
168
|
-
# need to change something
|
169
|
-
|
170
|
-
self.update active: !self.active
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
class TheAbstractClass < ActiveRecord::Base
|
176
|
-
self.abstract_class = true
|
177
|
-
self.table_name = 'mixins'
|
178
|
-
end
|
179
|
-
|
180
|
-
class TheAbstractSubclass < TheAbstractClass
|
181
|
-
acts_as_list column: "pos", scope: :parent
|
182
|
-
end
|
183
|
-
|
184
|
-
class TheBaseClass < ActiveRecord::Base
|
185
|
-
self.table_name = 'mixins'
|
186
|
-
acts_as_list column: "pos", scope: :parent
|
187
|
-
end
|
188
|
-
|
189
|
-
class TheBaseSubclass < TheBaseClass
|
190
|
-
end
|
191
|
-
|
192
|
-
class QuotedList < ActiveRecord::Base
|
193
|
-
self.table_name = 'table-name'
|
194
|
-
acts_as_list column: :order
|
195
|
-
end
|
196
|
-
|
197
|
-
class ActsAsListTestCase < Minitest::Test
|
198
|
-
# No default test required as this class is abstract.
|
199
|
-
# Need for test/unit.
|
200
|
-
undef_method :default_test if method_defined?(:default_test)
|
201
|
-
|
202
|
-
def teardown
|
203
|
-
teardown_db
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
class ZeroBasedTest < ActsAsListTestCase
|
208
|
-
include Shared::ZeroBased
|
209
|
-
|
210
|
-
def setup
|
211
|
-
setup_db
|
212
|
-
super
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
class ZeroBasedTestWithDefault < ActsAsListTestCase
|
217
|
-
include Shared::ZeroBased
|
218
|
-
|
219
|
-
def setup
|
220
|
-
setup_db_with_default
|
221
|
-
super
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
class ListTest < ActsAsListTestCase
|
226
|
-
include Shared::List
|
227
|
-
|
228
|
-
def setup
|
229
|
-
setup_db
|
230
|
-
super
|
231
|
-
end
|
232
|
-
|
233
|
-
def test_insert_race_condition
|
234
|
-
# the bigger n is the more likely we will have a race condition
|
235
|
-
n = 1000
|
236
|
-
(1..n).each do |counter|
|
237
|
-
node = ListMixin.new parent_id: 1
|
238
|
-
node.pos = counter
|
239
|
-
node.save!
|
240
|
-
end
|
241
|
-
|
242
|
-
wait_for_it = true
|
243
|
-
threads = []
|
244
|
-
4.times do |i|
|
245
|
-
threads << Thread.new do
|
246
|
-
true while wait_for_it
|
247
|
-
ActiveRecord::Base.connection_pool.with_connection do |c|
|
248
|
-
n.times do
|
249
|
-
begin
|
250
|
-
ListMixin.where(parent_id: 1).order('pos').last.insert_at(1)
|
251
|
-
rescue Exception
|
252
|
-
# ignore SQLite3::SQLException due to table locking
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|
258
|
-
wait_for_it = false
|
259
|
-
threads.each(&:join)
|
260
|
-
|
261
|
-
assert_equal((1..n).to_a, ListMixin.where(parent_id: 1).order('pos').map(&:pos))
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
class ListWithCallbackTest < ActsAsListTestCase
|
266
|
-
|
267
|
-
include Shared::List
|
268
|
-
|
269
|
-
def setup
|
270
|
-
ListMixin.send(:include, CallbackMixin)
|
271
|
-
setup_db
|
272
|
-
super
|
273
|
-
end
|
274
|
-
|
275
|
-
end
|
276
|
-
|
277
|
-
class ListTestWithDefault < ActsAsListTestCase
|
278
|
-
include Shared::List
|
279
|
-
|
280
|
-
def setup
|
281
|
-
setup_db_with_default
|
282
|
-
super
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
|
-
class ListSubTest < ActsAsListTestCase
|
287
|
-
include Shared::ListSub
|
288
|
-
|
289
|
-
def setup
|
290
|
-
setup_db
|
291
|
-
super
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
class ListSubTestWithDefault < ActsAsListTestCase
|
296
|
-
include Shared::ListSub
|
297
|
-
|
298
|
-
def setup
|
299
|
-
setup_db_with_default
|
300
|
-
super
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
class ArrayScopeListTest < ActsAsListTestCase
|
305
|
-
include Shared::ArrayScopeList
|
306
|
-
|
307
|
-
def setup
|
308
|
-
setup_db
|
309
|
-
super
|
310
|
-
end
|
311
|
-
end
|
312
|
-
|
313
|
-
class ArrayScopeListTestWithDefault < ActsAsListTestCase
|
314
|
-
include Shared::ArrayScopeList
|
315
|
-
|
316
|
-
def setup
|
317
|
-
setup_db_with_default
|
318
|
-
super
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
|
-
class QuotingTestList < ActsAsListTestCase
|
323
|
-
include Shared::Quoting
|
324
|
-
|
325
|
-
def setup
|
326
|
-
setup_db_with_default
|
327
|
-
super
|
328
|
-
end
|
329
|
-
end
|
330
|
-
|
331
|
-
class DefaultScopedTest < ActsAsListTestCase
|
332
|
-
def setup
|
333
|
-
setup_db
|
334
|
-
(1..4).each { |counter| DefaultScopedMixin.create!({pos: counter}) }
|
335
|
-
end
|
336
|
-
|
337
|
-
def test_insert
|
338
|
-
new = DefaultScopedMixin.create
|
339
|
-
assert_equal 5, new.pos
|
340
|
-
assert !new.first?
|
341
|
-
assert new.last?
|
342
|
-
|
343
|
-
new = DefaultScopedMixin.create
|
344
|
-
assert_equal 6, new.pos
|
345
|
-
assert !new.first?
|
346
|
-
assert new.last?
|
347
|
-
|
348
|
-
new = DefaultScopedMixin.acts_as_list_no_update { DefaultScopedMixin.create }
|
349
|
-
assert_equal_or_nil $default_position, new.pos
|
350
|
-
assert_equal $default_position.is_a?(Integer), new.first?
|
351
|
-
assert !new.last?
|
352
|
-
|
353
|
-
new = DefaultScopedMixin.create
|
354
|
-
assert_equal 7, new.pos
|
355
|
-
assert !new.first?
|
356
|
-
assert new.last?
|
357
|
-
end
|
358
|
-
|
359
|
-
def test_reordering
|
360
|
-
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
|
361
|
-
|
362
|
-
DefaultScopedMixin.where(id: 2).first.move_lower
|
363
|
-
assert_equal [1, 3, 2, 4], DefaultScopedMixin.all.map(&:id)
|
364
|
-
|
365
|
-
DefaultScopedMixin.where(id: 2).first.move_higher
|
366
|
-
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
|
367
|
-
|
368
|
-
DefaultScopedMixin.where(id: 1).first.move_to_bottom
|
369
|
-
assert_equal [2, 3, 4, 1], DefaultScopedMixin.all.map(&:id)
|
370
|
-
|
371
|
-
DefaultScopedMixin.where(id: 1).first.move_to_top
|
372
|
-
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
|
373
|
-
|
374
|
-
DefaultScopedMixin.where(id: 2).first.move_to_bottom
|
375
|
-
assert_equal [1, 3, 4, 2], DefaultScopedMixin.all.map(&:id)
|
376
|
-
|
377
|
-
DefaultScopedMixin.where(id: 4).first.move_to_top
|
378
|
-
assert_equal [4, 1, 3, 2], DefaultScopedMixin.all.map(&:id)
|
379
|
-
end
|
380
|
-
|
381
|
-
def test_insert_at
|
382
|
-
new = DefaultScopedMixin.create
|
383
|
-
assert_equal 5, new.pos
|
384
|
-
|
385
|
-
new = DefaultScopedMixin.create
|
386
|
-
assert_equal 6, new.pos
|
387
|
-
|
388
|
-
new_noup = DefaultScopedMixin.acts_as_list_no_update { DefaultScopedMixin.create }
|
389
|
-
assert_equal_or_nil $default_position, new_noup.pos
|
390
|
-
|
391
|
-
new = DefaultScopedMixin.create
|
392
|
-
assert_equal 7, new.pos
|
393
|
-
|
394
|
-
new4 = DefaultScopedMixin.create
|
395
|
-
assert_equal 8, new4.pos
|
396
|
-
|
397
|
-
new4.insert_at(2)
|
398
|
-
assert_equal 2, new4.pos
|
399
|
-
|
400
|
-
new.reload
|
401
|
-
assert_equal 8, new.pos
|
402
|
-
|
403
|
-
new.insert_at(2)
|
404
|
-
assert_equal 2, new.pos
|
405
|
-
|
406
|
-
new4.reload
|
407
|
-
assert_equal 3, new4.pos
|
408
|
-
|
409
|
-
new5 = DefaultScopedMixin.create
|
410
|
-
assert_equal 9, new5.pos
|
411
|
-
|
412
|
-
new5.insert_at(1)
|
413
|
-
assert_equal 1, new5.pos
|
414
|
-
|
415
|
-
new4.reload
|
416
|
-
assert_equal 4, new4.pos
|
417
|
-
|
418
|
-
new_noup.reload
|
419
|
-
assert_equal_or_nil $default_position, new_noup.pos
|
420
|
-
end
|
421
|
-
|
422
|
-
def test_find_or_create_doesnt_raise_deprecation_warning
|
423
|
-
assert_no_deprecation_warning_raised_by('ActiveRecord deprecation warning raised when using `find_or_create_by` when we didn\'t expect it') do
|
424
|
-
DefaultScopedMixin.find_or_create_by(pos: 5)
|
425
|
-
end
|
426
|
-
end
|
427
|
-
|
428
|
-
def test_update_position
|
429
|
-
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
|
430
|
-
DefaultScopedMixin.where(id: 2).first.set_list_position(4)
|
431
|
-
assert_equal [1, 3, 4, 2], DefaultScopedMixin.all.map(&:id)
|
432
|
-
DefaultScopedMixin.where(id: 2).first.set_list_position(2)
|
433
|
-
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
|
434
|
-
DefaultScopedMixin.where(id: 1).first.set_list_position(4)
|
435
|
-
assert_equal [2, 3, 4, 1], DefaultScopedMixin.all.map(&:id)
|
436
|
-
DefaultScopedMixin.where(id: 1).first.set_list_position(1)
|
437
|
-
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
|
438
|
-
end
|
439
|
-
end
|
440
|
-
|
441
|
-
class DefaultScopedWhereTest < ActsAsListTestCase
|
442
|
-
def setup
|
443
|
-
setup_db
|
444
|
-
(1..4).each { |counter| DefaultScopedWhereMixin.create! pos: counter, active: false }
|
445
|
-
end
|
446
|
-
|
447
|
-
def test_insert
|
448
|
-
new = DefaultScopedWhereMixin.create
|
449
|
-
assert_equal 5, new.pos
|
450
|
-
assert !new.first?
|
451
|
-
assert new.last?
|
452
|
-
|
453
|
-
new = DefaultScopedWhereMixin.create
|
454
|
-
assert_equal 6, new.pos
|
455
|
-
assert !new.first?
|
456
|
-
assert new.last?
|
457
|
-
|
458
|
-
new = DefaultScopedWhereMixin.acts_as_list_no_update { DefaultScopedWhereMixin.create }
|
459
|
-
assert_equal_or_nil $default_position, new.pos
|
460
|
-
assert_equal $default_position.is_a?(Integer), new.first?
|
461
|
-
assert !new.last?
|
462
|
-
|
463
|
-
new = DefaultScopedWhereMixin.create
|
464
|
-
assert_equal 7, new.pos
|
465
|
-
assert !new.first?
|
466
|
-
assert new.last?
|
467
|
-
end
|
468
|
-
|
469
|
-
def test_reordering
|
470
|
-
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
471
|
-
|
472
|
-
DefaultScopedWhereMixin.for_active_false_tests.where(id: 2).first.move_lower
|
473
|
-
assert_equal [1, 3, 2, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
474
|
-
|
475
|
-
DefaultScopedWhereMixin.for_active_false_tests.where(id: 2).first.move_higher
|
476
|
-
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
477
|
-
|
478
|
-
DefaultScopedWhereMixin.for_active_false_tests.where(id: 1).first.move_to_bottom
|
479
|
-
assert_equal [2, 3, 4, 1], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
480
|
-
|
481
|
-
DefaultScopedWhereMixin.for_active_false_tests.where(id: 1).first.move_to_top
|
482
|
-
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
483
|
-
|
484
|
-
DefaultScopedWhereMixin.for_active_false_tests.where(id: 2).first.move_to_bottom
|
485
|
-
assert_equal [1, 3, 4, 2], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
486
|
-
|
487
|
-
DefaultScopedWhereMixin.for_active_false_tests.where(id: 4).first.move_to_top
|
488
|
-
assert_equal [4, 1, 3, 2], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
489
|
-
end
|
490
|
-
|
491
|
-
def test_insert_at
|
492
|
-
new = DefaultScopedWhereMixin.create
|
493
|
-
assert_equal 5, new.pos
|
494
|
-
|
495
|
-
new = DefaultScopedWhereMixin.create
|
496
|
-
assert_equal 6, new.pos
|
497
|
-
|
498
|
-
new = DefaultScopedWhereMixin.create
|
499
|
-
assert_equal 7, new.pos
|
500
|
-
|
501
|
-
new_noup = DefaultScopedWhereMixin.acts_as_list_no_update { DefaultScopedWhereMixin.create }
|
502
|
-
assert_equal_or_nil $default_position, new_noup.pos
|
503
|
-
|
504
|
-
new4 = DefaultScopedWhereMixin.create
|
505
|
-
assert_equal 8, new4.pos
|
506
|
-
|
507
|
-
new4.insert_at(2)
|
508
|
-
assert_equal 2, new4.pos
|
509
|
-
|
510
|
-
new.reload
|
511
|
-
assert_equal 8, new.pos
|
512
|
-
|
513
|
-
new.insert_at(2)
|
514
|
-
assert_equal 2, new.pos
|
515
|
-
|
516
|
-
new4.reload
|
517
|
-
assert_equal 3, new4.pos
|
518
|
-
|
519
|
-
new5 = DefaultScopedWhereMixin.create
|
520
|
-
assert_equal 9, new5.pos
|
521
|
-
|
522
|
-
new5.insert_at(1)
|
523
|
-
assert_equal 1, new5.pos
|
524
|
-
|
525
|
-
new4.reload
|
526
|
-
assert_equal 4, new4.pos
|
527
|
-
|
528
|
-
new_noup.reload
|
529
|
-
assert_equal_or_nil $default_position, new_noup.pos
|
530
|
-
end
|
531
|
-
|
532
|
-
def test_find_or_create_doesnt_raise_deprecation_warning
|
533
|
-
assert_no_deprecation_warning_raised_by('ActiveRecord deprecation warning raised when using `find_or_create_by` when we didn\'t expect it') do
|
534
|
-
DefaultScopedWhereMixin.find_or_create_by(pos: 5)
|
535
|
-
end
|
536
|
-
end
|
537
|
-
|
538
|
-
def test_update_position
|
539
|
-
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
540
|
-
DefaultScopedWhereMixin.for_active_false_tests.where(id: 2).first.set_list_position(4)
|
541
|
-
assert_equal [1, 3, 4, 2], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
542
|
-
DefaultScopedWhereMixin.for_active_false_tests.where(id: 2).first.set_list_position(2)
|
543
|
-
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
544
|
-
DefaultScopedWhereMixin.for_active_false_tests.where(id: 1).first.set_list_position(4)
|
545
|
-
assert_equal [2, 3, 4, 1], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
546
|
-
DefaultScopedWhereMixin.for_active_false_tests.where(id: 1).first.set_list_position(1)
|
547
|
-
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
|
548
|
-
end
|
549
|
-
|
550
|
-
end
|
551
|
-
|
552
|
-
class MultiDestroyTest < ActsAsListTestCase
|
553
|
-
|
554
|
-
def setup
|
555
|
-
setup_db
|
556
|
-
end
|
557
|
-
|
558
|
-
# example:
|
559
|
-
#
|
560
|
-
# class TodoList < ActiveRecord::Base
|
561
|
-
# has_many :todo_items, order: "position"
|
562
|
-
# accepts_nested_attributes_for :todo_items, allow_destroy: true
|
563
|
-
# end
|
564
|
-
#
|
565
|
-
# class TodoItem < ActiveRecord::Base
|
566
|
-
# belongs_to :todo_list
|
567
|
-
# acts_as_list scope: :todo_list
|
568
|
-
# end
|
569
|
-
#
|
570
|
-
# Assume that there are three items.
|
571
|
-
# The user mark two items as deleted, click save button, form will be post:
|
572
|
-
#
|
573
|
-
# todo_list.todo_items_attributes = [
|
574
|
-
# {id: 1, _destroy: true},
|
575
|
-
# {id: 2, _destroy: true}
|
576
|
-
# ]
|
577
|
-
#
|
578
|
-
# Save toto_list, the position of item #3 should eql 1.
|
579
|
-
#
|
580
|
-
def test_destroy
|
581
|
-
new1 = DefaultScopedMixin.create
|
582
|
-
assert_equal 1, new1.pos
|
583
|
-
|
584
|
-
new2 = DefaultScopedMixin.create
|
585
|
-
assert_equal 2, new2.pos
|
586
|
-
|
587
|
-
new3 = DefaultScopedMixin.create
|
588
|
-
assert_equal 3, new3.pos
|
589
|
-
|
590
|
-
new4 = DefaultScopedMixin.create
|
591
|
-
assert_equal 4, new4.pos
|
592
|
-
|
593
|
-
new1.destroy
|
594
|
-
new2.destroy
|
595
|
-
new3.reload
|
596
|
-
new4.reload
|
597
|
-
assert_equal 1, new3.pos
|
598
|
-
assert_equal 2, new4.pos
|
599
|
-
|
600
|
-
DefaultScopedMixin.acts_as_list_no_update { new3.destroy }
|
601
|
-
|
602
|
-
new4.reload
|
603
|
-
assert_equal 2, new4.pos
|
604
|
-
end
|
605
|
-
end
|
606
|
-
|
607
|
-
#class TopAdditionMixin < Mixin
|
608
|
-
|
609
|
-
class TopAdditionTest < ActsAsListTestCase
|
610
|
-
include Shared::TopAddition
|
611
|
-
|
612
|
-
def setup
|
613
|
-
setup_db
|
614
|
-
super
|
615
|
-
end
|
616
|
-
end
|
617
|
-
|
618
|
-
class TopAdditionTestWithDefault < ActsAsListTestCase
|
619
|
-
include Shared::TopAddition
|
620
|
-
|
621
|
-
def setup
|
622
|
-
setup_db_with_default
|
623
|
-
super
|
624
|
-
end
|
625
|
-
end
|
626
|
-
|
627
|
-
class NoAdditionTest < ActsAsListTestCase
|
628
|
-
include Shared::NoAddition
|
629
|
-
|
630
|
-
def setup
|
631
|
-
setup_db
|
632
|
-
super
|
633
|
-
end
|
634
|
-
end
|
635
|
-
|
636
|
-
class MultipleListsTest < ActsAsListTestCase
|
637
|
-
def setup
|
638
|
-
setup_db
|
639
|
-
(1..4).each { |counter| ListMixin.create! :pos => counter, :parent_id => 1}
|
640
|
-
(1..4).each { |counter| ListMixin.create! :pos => counter, :parent_id => 2}
|
641
|
-
end
|
642
|
-
|
643
|
-
def test_check_scope_order
|
644
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 1).order('pos').map(&:id)
|
645
|
-
assert_equal [5, 6, 7, 8], ListMixin.where(:parent_id => 2).order('pos').map(&:id)
|
646
|
-
ListMixin.find(4).update :parent_id => 2, :pos => 2
|
647
|
-
assert_equal [1, 2, 3], ListMixin.where(:parent_id => 1).order('pos').map(&:id)
|
648
|
-
assert_equal [5, 4, 6, 7, 8], ListMixin.where(:parent_id => 2).order('pos').map(&:id)
|
649
|
-
end
|
650
|
-
|
651
|
-
def test_check_scope_position
|
652
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 1).map(&:pos)
|
653
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 2).map(&:pos)
|
654
|
-
ListMixin.find(4).update :parent_id => 2, :pos => 2
|
655
|
-
assert_equal [1, 2, 3], ListMixin.where(:parent_id => 1).order('pos').map(&:pos)
|
656
|
-
assert_equal [1, 2, 3, 4, 5], ListMixin.where(:parent_id => 2).order('pos').map(&:pos)
|
657
|
-
end
|
658
|
-
|
659
|
-
def test_find_or_create_doesnt_raise_deprecation_warning
|
660
|
-
assert_no_deprecation_warning_raised_by('ActiveRecord deprecation warning raised when using `find_or_create_by` when we didn\'t expect it') do
|
661
|
-
ListMixin.where(:parent_id => 1).find_or_create_by(pos: 5)
|
662
|
-
end
|
663
|
-
end
|
664
|
-
end
|
665
|
-
|
666
|
-
class EnumArrayScopeListMixinTest < ActsAsListTestCase
|
667
|
-
def setup
|
668
|
-
setup_db
|
669
|
-
EnumArrayScopeListMixin.create! :parent_id => 1, :state => EnumArrayScopeListMixin.states['active']
|
670
|
-
EnumArrayScopeListMixin.create! :parent_id => 1, :state => EnumArrayScopeListMixin.states['archived']
|
671
|
-
EnumArrayScopeListMixin.create! :parent_id => 2, :state => EnumArrayScopeListMixin.states["active"]
|
672
|
-
EnumArrayScopeListMixin.create! :parent_id => 2, :state => EnumArrayScopeListMixin.states["archived"]
|
673
|
-
end
|
674
|
-
|
675
|
-
def test_positions
|
676
|
-
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 1, :state => EnumArrayScopeListMixin.states['active']).map(&:pos)
|
677
|
-
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 1, :state => EnumArrayScopeListMixin.states['archived']).map(&:pos)
|
678
|
-
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['active']).map(&:pos)
|
679
|
-
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['archived']).map(&:pos)
|
680
|
-
end
|
681
|
-
|
682
|
-
def test_update_state
|
683
|
-
active_item = EnumArrayScopeListMixin.find_by(:parent_id => 2, :state => EnumArrayScopeListMixin.states['active'])
|
684
|
-
active_item.update(state: EnumArrayScopeListMixin.states['archived'])
|
685
|
-
assert_equal [1, 2], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['archived']).map(&:pos).sort
|
686
|
-
end
|
687
|
-
end
|
688
|
-
|
689
|
-
class MultipleListsArrayScopeTest < ActsAsListTestCase
|
690
|
-
def setup
|
691
|
-
setup_db
|
692
|
-
(1..4).each { |counter| ArrayScopeListMixin.create! :pos => counter,:parent_id => 1, :parent_type => 'anything'}
|
693
|
-
(1..4).each { |counter| ArrayScopeListMixin.create! :pos => counter,:parent_id => 2, :parent_type => 'something'}
|
694
|
-
(1..4).each { |counter| ArrayScopeListMixin.create! :pos => counter,:parent_id => 3, :parent_type => 'anything'}
|
695
|
-
end
|
696
|
-
|
697
|
-
def test_order_after_all_scope_properties_are_changed
|
698
|
-
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:id)
|
699
|
-
assert_equal [5, 6, 7, 8], ArrayScopeListMixin.where(:parent_id => 2, :parent_type => 'something').order('pos').map(&:id)
|
700
|
-
ArrayScopeListMixin.find(2).update :parent_id => 2, :pos => 2,:parent_type => 'something'
|
701
|
-
assert_equal [1, 3, 4], ArrayScopeListMixin.where(:parent_id => 1,:parent_type => 'anything').order('pos').map(&:id)
|
702
|
-
assert_equal [5, 2, 6, 7, 8], ArrayScopeListMixin.where(:parent_id => 2,:parent_type => 'something').order('pos').map(&:id)
|
703
|
-
end
|
704
|
-
|
705
|
-
def test_position_after_all_scope_properties_are_changed
|
706
|
-
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').map(&:pos)
|
707
|
-
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 2, :parent_type => 'something').map(&:pos)
|
708
|
-
ArrayScopeListMixin.find(4).update :parent_id => 2, :pos => 2, :parent_type => 'something'
|
709
|
-
assert_equal [1, 2, 3], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:pos)
|
710
|
-
assert_equal [1, 2, 3, 4, 5], ArrayScopeListMixin.where(:parent_id => 2, :parent_type => 'something').order('pos').map(&:pos)
|
711
|
-
end
|
712
|
-
|
713
|
-
def test_order_after_one_scope_property_is_changed
|
714
|
-
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:id)
|
715
|
-
assert_equal [9, 10, 11, 12], ArrayScopeListMixin.where(:parent_id => 3, :parent_type => 'anything').order('pos').map(&:id)
|
716
|
-
ArrayScopeListMixin.find(2).update :parent_id => 3, :pos => 2
|
717
|
-
assert_equal [1, 3, 4], ArrayScopeListMixin.where(:parent_id => 1,:parent_type => 'anything').order('pos').map(&:id)
|
718
|
-
assert_equal [9, 2, 10, 11, 12], ArrayScopeListMixin.where(:parent_id => 3,:parent_type => 'anything').order('pos').map(&:id)
|
719
|
-
end
|
720
|
-
|
721
|
-
def test_position_after_one_scope_property_is_changed
|
722
|
-
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').map(&:pos)
|
723
|
-
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 3, :parent_type => 'anything').map(&:pos)
|
724
|
-
ArrayScopeListMixin.find(4).update :parent_id => 3, :pos => 2
|
725
|
-
assert_equal [1, 2, 3], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:pos)
|
726
|
-
assert_equal [1, 2, 3, 4, 5], ArrayScopeListMixin.where(:parent_id => 3, :parent_type => 'anything').order('pos').map(&:pos)
|
727
|
-
end
|
728
|
-
|
729
|
-
def test_order_after_moving_to_empty_list
|
730
|
-
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:id)
|
731
|
-
assert_equal [], ArrayScopeListMixin.where(:parent_id => 4, :parent_type => 'anything').order('pos').map(&:id)
|
732
|
-
ArrayScopeListMixin.find(2).update :parent_id => 4, :pos => 1
|
733
|
-
assert_equal [1, 3, 4], ArrayScopeListMixin.where(:parent_id => 1,:parent_type => 'anything').order('pos').map(&:id)
|
734
|
-
assert_equal [2], ArrayScopeListMixin.where(:parent_id => 4,:parent_type => 'anything').order('pos').map(&:id)
|
735
|
-
end
|
736
|
-
|
737
|
-
def test_position_after_moving_to_empty_list
|
738
|
-
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').map(&:pos)
|
739
|
-
assert_equal [], ArrayScopeListMixin.where(:parent_id => 4, :parent_type => 'anything').map(&:pos)
|
740
|
-
ArrayScopeListMixin.find(2).update :parent_id => 4, :pos => 1
|
741
|
-
assert_equal [1, 2, 3], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:pos)
|
742
|
-
assert_equal [1], ArrayScopeListMixin.where(:parent_id => 4, :parent_type => 'anything').order('pos').map(&:pos)
|
743
|
-
end
|
744
|
-
end
|
745
|
-
|
746
|
-
class ArrayScopeListWithHashTest
|
747
|
-
def setup
|
748
|
-
setup_db
|
749
|
-
@obj1 = ArrayScopeListWithHashMixin.create! :pos => counter, :parent_id => 1, :state => nil
|
750
|
-
@obj2 = ArrayScopeListWithHashMixin.create! :pos => counter, :parent_id => 1, :state => 'anything'
|
751
|
-
end
|
752
|
-
|
753
|
-
def test_scope_condition_correct
|
754
|
-
[@obj1, @obj2].each do |obj|
|
755
|
-
assert_equal({ :parent_id => 1, :state => nil }, obj.scope_condition)
|
756
|
-
end
|
757
|
-
end
|
758
|
-
end
|
759
|
-
|
760
|
-
require 'timecop'
|
761
|
-
|
762
|
-
class TouchTest < ActsAsListTestCase
|
763
|
-
def setup
|
764
|
-
setup_db
|
765
|
-
Timecop.freeze(yesterday) do
|
766
|
-
4.times { ListMixin.create! }
|
767
|
-
end
|
768
|
-
end
|
769
|
-
|
770
|
-
def now
|
771
|
-
@now ||= Time.current.change(usec: 0)
|
772
|
-
end
|
773
|
-
|
774
|
-
def yesterday
|
775
|
-
@yesterday ||= 1.day.ago
|
776
|
-
end
|
777
|
-
|
778
|
-
def updated_ats
|
779
|
-
ListMixin.order(:id).pluck(:updated_at)
|
780
|
-
end
|
781
|
-
|
782
|
-
def test_moving_item_lower_touches_self_and_lower_item
|
783
|
-
Timecop.freeze(now) do
|
784
|
-
ListMixin.first.move_lower
|
785
|
-
updated_ats[0..1].each do |updated_at|
|
786
|
-
assert_equal updated_at.to_i, now.to_i
|
787
|
-
end
|
788
|
-
updated_ats[2..3].each do |updated_at|
|
789
|
-
assert_equal updated_at.to_i, yesterday.to_i
|
790
|
-
end
|
791
|
-
end
|
792
|
-
end
|
793
|
-
|
794
|
-
def test_moving_item_higher_touches_self_and_higher_item
|
795
|
-
Timecop.freeze(now) do
|
796
|
-
ListMixin.all.second.move_higher
|
797
|
-
updated_ats[0..1].each do |updated_at|
|
798
|
-
assert_equal updated_at.to_i, now.to_i
|
799
|
-
end
|
800
|
-
updated_ats[2..3].each do |updated_at|
|
801
|
-
assert_equal updated_at.to_i, yesterday.to_i
|
802
|
-
end
|
803
|
-
end
|
804
|
-
end
|
805
|
-
|
806
|
-
def test_moving_item_to_bottom_touches_all_other_items
|
807
|
-
Timecop.freeze(now) do
|
808
|
-
ListMixin.first.move_to_bottom
|
809
|
-
updated_ats.each do |updated_at|
|
810
|
-
assert_equal updated_at.to_i, now.to_i
|
811
|
-
end
|
812
|
-
end
|
813
|
-
end
|
814
|
-
|
815
|
-
def test_moving_item_to_top_touches_all_other_items
|
816
|
-
Timecop.freeze(now) do
|
817
|
-
ListMixin.last.move_to_top
|
818
|
-
updated_ats.each do |updated_at|
|
819
|
-
assert_equal updated_at.to_i, now.to_i
|
820
|
-
end
|
821
|
-
end
|
822
|
-
end
|
823
|
-
|
824
|
-
def test_removing_item_touches_all_lower_items
|
825
|
-
Timecop.freeze(now) do
|
826
|
-
ListMixin.all.third.remove_from_list
|
827
|
-
updated_ats[0..1].each do |updated_at|
|
828
|
-
assert_equal updated_at.to_i, yesterday.to_i
|
829
|
-
end
|
830
|
-
updated_ats[2..2].each do |updated_at|
|
831
|
-
assert_equal updated_at.to_i, now.to_i
|
832
|
-
end
|
833
|
-
end
|
834
|
-
end
|
835
|
-
end
|
836
|
-
|
837
|
-
class TouchDisabledTest < ActsAsListTestCase
|
838
|
-
def setup
|
839
|
-
setup_db
|
840
|
-
Timecop.freeze(yesterday) do
|
841
|
-
4.times { TouchDisabledMixin.create! }
|
842
|
-
end
|
843
|
-
end
|
844
|
-
|
845
|
-
def now
|
846
|
-
@now ||= Time.current.change(usec: 0)
|
847
|
-
end
|
848
|
-
|
849
|
-
def yesterday
|
850
|
-
@yesterday ||= 1.day.ago
|
851
|
-
end
|
852
|
-
|
853
|
-
def updated_ats
|
854
|
-
TouchDisabledMixin.order(:id).pluck(:updated_at)
|
855
|
-
end
|
856
|
-
|
857
|
-
def positions
|
858
|
-
ListMixin.order(:id).pluck(:pos)
|
859
|
-
end
|
860
|
-
|
861
|
-
def test_deleting_item_does_not_touch_higher_items
|
862
|
-
Timecop.freeze(now) do
|
863
|
-
TouchDisabledMixin.first.destroy
|
864
|
-
updated_ats.each do |updated_at|
|
865
|
-
assert_equal updated_at.to_i, yesterday.to_i
|
866
|
-
end
|
867
|
-
assert_equal positions, [1, 2, 3]
|
868
|
-
end
|
869
|
-
end
|
870
|
-
end
|
871
|
-
|
872
|
-
class ActsAsListTopTest < ActsAsListTestCase
|
873
|
-
def setup
|
874
|
-
setup_db
|
875
|
-
end
|
876
|
-
|
877
|
-
def test_acts_as_list_top
|
878
|
-
assert_equal 1, TheBaseSubclass.new.acts_as_list_top
|
879
|
-
assert_equal 0, ZeroBasedMixin.new.acts_as_list_top
|
880
|
-
end
|
881
|
-
|
882
|
-
def test_class_acts_as_list_top
|
883
|
-
assert_equal 1, TheBaseSubclass.acts_as_list_top
|
884
|
-
assert_equal 0, ZeroBasedMixin.acts_as_list_top
|
885
|
-
end
|
886
|
-
end
|
887
|
-
|
888
|
-
class NilPositionTest < ActsAsListTestCase
|
889
|
-
def setup
|
890
|
-
setup_db
|
891
|
-
end
|
892
|
-
|
893
|
-
def test_nil_position_ordering
|
894
|
-
new1 = DefaultScopedMixin.create pos: nil
|
895
|
-
new2 = DefaultScopedMixin.create pos: nil
|
896
|
-
new3 = DefaultScopedMixin.create pos: nil
|
897
|
-
DefaultScopedMixin.update_all(pos: nil)
|
898
|
-
|
899
|
-
assert_equal [nil, nil, nil], DefaultScopedMixin.all.map(&:pos)
|
900
|
-
|
901
|
-
new1.reload.pos = 1
|
902
|
-
new1.save
|
903
|
-
|
904
|
-
new3.reload.pos = 1
|
905
|
-
new3.save
|
906
|
-
|
907
|
-
assert_equal [1, 2], DefaultScopedMixin.where("pos IS NOT NULL").map(&:pos)
|
908
|
-
assert_equal [3, 1], DefaultScopedMixin.where("pos IS NOT NULL").map(&:id)
|
909
|
-
assert_nil new2.reload.pos
|
910
|
-
|
911
|
-
new2.reload.pos = 1
|
912
|
-
new2.save
|
913
|
-
|
914
|
-
assert_equal [1, 2, 3], DefaultScopedMixin.all.map(&:pos)
|
915
|
-
assert_equal [2, 3, 1], DefaultScopedMixin.all.map(&:id)
|
916
|
-
end
|
917
|
-
end
|
918
|
-
|
919
|
-
class SequentialUpdatesOptionDefaultTest < ActsAsListTestCase
|
920
|
-
def setup
|
921
|
-
setup_db
|
922
|
-
end
|
923
|
-
|
924
|
-
def test_sequential_updates_default_to_false_without_unique_index
|
925
|
-
assert_equal false, SequentialUpdatesDefault.new.send(:sequential_updates?)
|
926
|
-
end
|
927
|
-
end
|
928
|
-
|
929
|
-
class SequentialUpdatesMixinNotNullUniquePositiveConstraintsTest < ActsAsListTestCase
|
930
|
-
def setup
|
931
|
-
setup_db null: false, unique: true, positive: true
|
932
|
-
(1..4).each { |counter| SequentialUpdatesDefault.create!({pos: counter}) }
|
933
|
-
end
|
934
|
-
|
935
|
-
def test_sequential_updates_default_to_true_with_unique_index
|
936
|
-
assert_equal true, SequentialUpdatesDefault.new.send(:sequential_updates?)
|
937
|
-
end
|
938
|
-
|
939
|
-
def test_sequential_updates_option_override_with_false
|
940
|
-
assert_equal false, SequentialUpdatesFalseMixin.new.send(:sequential_updates?)
|
941
|
-
end
|
942
|
-
|
943
|
-
def test_insert_at
|
944
|
-
new = SequentialUpdatesDefault.create
|
945
|
-
assert_equal 5, new.pos
|
946
|
-
|
947
|
-
new.insert_at(1)
|
948
|
-
assert_equal 1, new.pos
|
949
|
-
|
950
|
-
new.insert_at(5)
|
951
|
-
assert_equal 5, new.pos
|
952
|
-
|
953
|
-
new.insert_at(3)
|
954
|
-
assert_equal 3, new.pos
|
955
|
-
end
|
956
|
-
|
957
|
-
def test_move_to_bottom
|
958
|
-
item = SequentialUpdatesDefault.order(:pos).first
|
959
|
-
item.move_to_bottom
|
960
|
-
assert_equal 4, item.pos
|
961
|
-
end
|
962
|
-
|
963
|
-
def test_move_to_top
|
964
|
-
new_item = SequentialUpdatesDefault.create!
|
965
|
-
assert_equal 5, new_item.pos
|
966
|
-
|
967
|
-
new_item.move_to_top
|
968
|
-
assert_equal 1, new_item.pos
|
969
|
-
end
|
970
|
-
|
971
|
-
def test_destroy
|
972
|
-
new_item = SequentialUpdatesDefault.create
|
973
|
-
assert_equal 5, new_item.pos
|
974
|
-
|
975
|
-
new_item.insert_at(2)
|
976
|
-
assert_equal 2, new_item.pos
|
977
|
-
|
978
|
-
new_item.destroy
|
979
|
-
assert_equal [1,2,3,4], SequentialUpdatesDefault.all.map(&:pos).sort
|
980
|
-
|
981
|
-
end
|
982
|
-
|
983
|
-
def test_exception_on_wrong_position
|
984
|
-
new_item = SequentialUpdatesDefault.create
|
985
|
-
|
986
|
-
assert_raises ArgumentError do
|
987
|
-
new_item.insert_at(0)
|
988
|
-
end
|
989
|
-
end
|
990
|
-
|
991
|
-
|
992
|
-
class SequentialUpdatesMixinNotNullUniquePositiveConstraintsTest < ActsAsListTestCase
|
993
|
-
def setup
|
994
|
-
setup_db null: false, unique: true, positive: true
|
995
|
-
(1..4).each { |counter| SequentialUpdatesAltId.create!({pos: counter}) }
|
996
|
-
end
|
997
|
-
|
998
|
-
def test_sequential_updates_default_to_true_with_unique_index
|
999
|
-
assert_equal true, SequentialUpdatesAltId.new.send(:sequential_updates?)
|
1000
|
-
end
|
1001
|
-
|
1002
|
-
def test_insert_at
|
1003
|
-
new = SequentialUpdatesAltId.create
|
1004
|
-
assert_equal 5, new.pos
|
1005
|
-
|
1006
|
-
new.insert_at(1)
|
1007
|
-
assert_equal 1, new.pos
|
1008
|
-
|
1009
|
-
new.insert_at(5)
|
1010
|
-
assert_equal 5, new.pos
|
1011
|
-
|
1012
|
-
new.insert_at(3)
|
1013
|
-
assert_equal 3, new.pos
|
1014
|
-
end
|
1015
|
-
|
1016
|
-
def test_create_at_top
|
1017
|
-
new = SequentialUpdatesAltId.create!(pos: 1)
|
1018
|
-
assert_equal 1, new.pos
|
1019
|
-
end
|
1020
|
-
|
1021
|
-
def test_move_to_bottom
|
1022
|
-
item = SequentialUpdatesAltId.order(:pos).first
|
1023
|
-
item.move_to_bottom
|
1024
|
-
assert_equal 4, item.pos
|
1025
|
-
end
|
1026
|
-
|
1027
|
-
def test_move_to_top
|
1028
|
-
new_item = SequentialUpdatesAltId.create!
|
1029
|
-
assert_equal 5, new_item.pos
|
1030
|
-
|
1031
|
-
new_item.move_to_top
|
1032
|
-
assert_equal 1, new_item.pos
|
1033
|
-
end
|
1034
|
-
|
1035
|
-
def test_destroy
|
1036
|
-
new_item = SequentialUpdatesAltId.create
|
1037
|
-
assert_equal 5, new_item.pos
|
1038
|
-
|
1039
|
-
new_item.insert_at(2)
|
1040
|
-
assert_equal 2, new_item.pos
|
1041
|
-
|
1042
|
-
new_item.destroy
|
1043
|
-
assert_equal [1,2,3,4], SequentialUpdatesAltId.all.map(&:pos).sort
|
1044
|
-
|
1045
|
-
end
|
1046
|
-
end
|
1047
|
-
|
1048
|
-
class SequentialUpdatesAltIdTouchDisabledTest < ActsAsListTestCase
|
1049
|
-
def setup
|
1050
|
-
setup_db
|
1051
|
-
Timecop.freeze(yesterday) do
|
1052
|
-
4.times { SequentialUpdatesAltIdTouchDisabled.create! }
|
1053
|
-
end
|
1054
|
-
end
|
1055
|
-
|
1056
|
-
def now
|
1057
|
-
@now ||= Time.current.change(usec: 0)
|
1058
|
-
end
|
1059
|
-
|
1060
|
-
def yesterday
|
1061
|
-
@yesterday ||= 1.day.ago
|
1062
|
-
end
|
1063
|
-
|
1064
|
-
def updated_ats
|
1065
|
-
SequentialUpdatesAltIdTouchDisabled.order(:altid).pluck(:updated_at)
|
1066
|
-
end
|
1067
|
-
|
1068
|
-
def positions
|
1069
|
-
SequentialUpdatesAltIdTouchDisabled.order(:altid).pluck(:pos)
|
1070
|
-
end
|
1071
|
-
|
1072
|
-
def test_sequential_updates_default_to_true_with_unique_index
|
1073
|
-
assert_equal true, SequentialUpdatesAltIdTouchDisabled.new.send(:sequential_updates?)
|
1074
|
-
end
|
1075
|
-
|
1076
|
-
def test_deleting_item_does_not_touch_higher_items
|
1077
|
-
Timecop.freeze(now) do
|
1078
|
-
SequentialUpdatesAltIdTouchDisabled.first.destroy
|
1079
|
-
updated_ats.each do |updated_at|
|
1080
|
-
assert_equal updated_at.to_i, yesterday.to_i
|
1081
|
-
end
|
1082
|
-
assert_equal positions, [1, 2, 3]
|
1083
|
-
end
|
1084
|
-
end
|
1085
|
-
end
|
1086
|
-
end
|