acts_as_list 0.7.2 → 0.8.0
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 +5 -13
- data/.gitignore +2 -0
- data/.travis.yml +21 -0
- data/Appraisals +13 -3
- data/CHANGELOG.md +331 -0
- data/Gemfile +5 -2
- data/README.md +21 -6
- data/Rakefile +8 -0
- data/gemfiles/rails_3_2.gemfile +6 -2
- data/gemfiles/rails_4_1.gemfile +6 -8
- data/gemfiles/rails_4_2.gemfile +5 -2
- data/gemfiles/rails_5_0.gemfile +24 -0
- data/lib/acts_as_list/active_record/acts/list.rb +164 -129
- data/lib/acts_as_list/version.rb +1 -1
- data/test/helper.rb +7 -0
- data/test/shared.rb +1 -0
- data/test/shared_list.rb +13 -1
- data/test/shared_list_sub.rb +28 -2
- data/test/shared_no_addition.rb +11 -0
- data/test/shared_quoting.rb +21 -0
- data/test/shared_top_addition.rb +18 -12
- data/test/test_joined_list.rb +64 -0
- data/test/test_list.rb +183 -3
- metadata +17 -14
- data/gemfiles/rails_3_2.gemfile.lock +0 -258
- data/gemfiles/rails_4_1.gemfile.lock +0 -262
- data/gemfiles/rails_4_2.gemfile.lock +0 -53
|
@@ -38,32 +38,30 @@ module ActiveRecord
|
|
|
38
38
|
configuration = { column: "position", scope: "1 = 1", top_of_list: 1, add_new_at: :bottom}
|
|
39
39
|
configuration.update(options) if options.is_a?(Hash)
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
if configuration[:scope].is_a?(Symbol) && configuration[:scope].to_s !~ /_id$/
|
|
42
|
+
configuration[:scope] = :"#{configuration[:scope]}_id"
|
|
43
|
+
end
|
|
42
44
|
|
|
43
45
|
if configuration[:scope].is_a?(Symbol)
|
|
44
46
|
scope_methods = %(
|
|
45
47
|
def scope_condition
|
|
46
|
-
{
|
|
48
|
+
{ #{configuration[:scope]}: send(:#{configuration[:scope]}) }
|
|
47
49
|
end
|
|
48
50
|
|
|
49
51
|
def scope_changed?
|
|
50
|
-
|
|
52
|
+
changed.include?(scope_name.to_s)
|
|
51
53
|
end
|
|
52
54
|
)
|
|
53
55
|
elsif configuration[:scope].is_a?(Array)
|
|
54
56
|
scope_methods = %(
|
|
55
|
-
def
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
def scope_condition
|
|
58
|
+
#{configuration[:scope]}.inject({}) do |hash, column|
|
|
59
|
+
hash.merge!({ column.to_sym => read_attribute(column.to_sym) })
|
|
58
60
|
end
|
|
59
61
|
end
|
|
60
62
|
|
|
61
63
|
def scope_changed?
|
|
62
|
-
(
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def scope_condition
|
|
66
|
-
attrs
|
|
64
|
+
(scope_condition.keys & changed.map(&:to_sym)).any?
|
|
67
65
|
end
|
|
68
66
|
)
|
|
69
67
|
else
|
|
@@ -76,8 +74,13 @@ module ActiveRecord
|
|
|
76
74
|
)
|
|
77
75
|
end
|
|
78
76
|
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
quoted_position_column = connection.quote_column_name(configuration[:column])
|
|
78
|
+
quoted_position_column_with_table_name = "#{quoted_table_name}.#{quoted_position_column}"
|
|
79
|
+
|
|
80
|
+
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
|
81
|
+
def self.acts_as_list_top
|
|
82
|
+
#{configuration[:top_of_list]}.to_i
|
|
83
|
+
end
|
|
81
84
|
|
|
82
85
|
def acts_as_list_top
|
|
83
86
|
#{configuration[:top_of_list]}.to_i
|
|
@@ -113,19 +116,46 @@ module ActiveRecord
|
|
|
113
116
|
attr_accessible :#{configuration[:column]}
|
|
114
117
|
end
|
|
115
118
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
scope :in_list, lambda { where(%q{#{quoted_position_column_with_table_name} IS NOT NULL}) }
|
|
120
|
+
|
|
121
|
+
def self.decrement_all
|
|
122
|
+
update_all_with_touch %q(#{quoted_position_column} = (#{quoted_position_column_with_table_name} - 1))
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def self.increment_all
|
|
126
|
+
update_all_with_touch %q(#{quoted_position_column} = (#{quoted_position_column_with_table_name} + 1))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def self.update_all_with_touch(updates)
|
|
130
|
+
record = new
|
|
131
|
+
attrs = record.send(:timestamp_attributes_for_update_in_model)
|
|
132
|
+
now = record.send(:current_time_from_proper_timezone)
|
|
133
|
+
|
|
134
|
+
query = attrs.map { |attr| %(\#{connection.quote_column_name(attr)} = :now) }
|
|
135
|
+
query.push updates
|
|
136
|
+
query = query.join(", ")
|
|
121
137
|
|
|
122
|
-
|
|
138
|
+
update_all([query, now: now])
|
|
139
|
+
end
|
|
123
140
|
EOV
|
|
124
141
|
|
|
142
|
+
attr_reader :position_changed
|
|
143
|
+
|
|
144
|
+
before_validation :check_top_position
|
|
145
|
+
|
|
146
|
+
before_destroy :lock!
|
|
147
|
+
after_destroy :decrement_positions_on_lower_items
|
|
148
|
+
|
|
149
|
+
before_update :check_scope
|
|
150
|
+
after_update :update_positions
|
|
151
|
+
|
|
152
|
+
after_commit :clear_scope_changed
|
|
153
|
+
|
|
125
154
|
if configuration[:add_new_at].present?
|
|
126
|
-
|
|
155
|
+
before_create "add_to_list_#{configuration[:add_new_at]}".to_sym
|
|
127
156
|
end
|
|
128
157
|
|
|
158
|
+
include ::ActiveRecord::Acts::List::InstanceMethods
|
|
129
159
|
end
|
|
130
160
|
end
|
|
131
161
|
|
|
@@ -144,8 +174,12 @@ module ActiveRecord
|
|
|
144
174
|
return unless lower_item
|
|
145
175
|
|
|
146
176
|
acts_as_list_class.transaction do
|
|
147
|
-
lower_item.
|
|
148
|
-
|
|
177
|
+
if lower_item.send(position_column) != self.send(position_column)
|
|
178
|
+
swap_positions(lower_item, self)
|
|
179
|
+
else
|
|
180
|
+
lower_item.decrement_position
|
|
181
|
+
increment_position
|
|
182
|
+
end
|
|
149
183
|
end
|
|
150
184
|
end
|
|
151
185
|
|
|
@@ -154,8 +188,12 @@ module ActiveRecord
|
|
|
154
188
|
return unless higher_item
|
|
155
189
|
|
|
156
190
|
acts_as_list_class.transaction do
|
|
157
|
-
higher_item.
|
|
158
|
-
|
|
191
|
+
if higher_item.send(position_column) != self.send(position_column)
|
|
192
|
+
swap_positions(higher_item, self)
|
|
193
|
+
else
|
|
194
|
+
higher_item.increment_position
|
|
195
|
+
decrement_position
|
|
196
|
+
end
|
|
159
197
|
end
|
|
160
198
|
end
|
|
161
199
|
|
|
@@ -206,25 +244,20 @@ module ActiveRecord
|
|
|
206
244
|
set_list_position(self.send(position_column).to_i - 1)
|
|
207
245
|
end
|
|
208
246
|
|
|
209
|
-
# Return +true+ if this object is the first in the list.
|
|
210
247
|
def first?
|
|
211
248
|
return false unless in_list?
|
|
212
|
-
|
|
249
|
+
!higher_item
|
|
213
250
|
end
|
|
214
251
|
|
|
215
|
-
# Return +true+ if this object is the last in the list.
|
|
216
252
|
def last?
|
|
217
253
|
return false unless in_list?
|
|
218
|
-
|
|
254
|
+
!lower_item
|
|
219
255
|
end
|
|
220
256
|
|
|
221
257
|
# Return the next higher item in the list.
|
|
222
258
|
def higher_item
|
|
223
259
|
return nil unless in_list?
|
|
224
|
-
|
|
225
|
-
acts_as_list_class.where(scope_condition).where("#{position_column} < #{(send(position_column).to_i).to_s}").
|
|
226
|
-
order("#{acts_as_list_class.table_name}.#{position_column} DESC").first
|
|
227
|
-
end
|
|
260
|
+
higher_items(1).first
|
|
228
261
|
end
|
|
229
262
|
|
|
230
263
|
# Return the next n higher items in the list
|
|
@@ -233,19 +266,15 @@ module ActiveRecord
|
|
|
233
266
|
limit ||= acts_as_list_list.count
|
|
234
267
|
position_value = send(position_column)
|
|
235
268
|
acts_as_list_list.
|
|
236
|
-
where("#{
|
|
237
|
-
|
|
238
|
-
limit(limit)
|
|
239
|
-
order("#{acts_as_list_class.table_name}.#{position_column} ASC")
|
|
269
|
+
where("#{quoted_position_column_with_table_name} < ?", position_value).
|
|
270
|
+
order("#{quoted_position_column_with_table_name} DESC").
|
|
271
|
+
limit(limit)
|
|
240
272
|
end
|
|
241
273
|
|
|
242
274
|
# Return the next lower item in the list.
|
|
243
275
|
def lower_item
|
|
244
276
|
return nil unless in_list?
|
|
245
|
-
|
|
246
|
-
acts_as_list_class.where(scope_condition).where("#{position_column} > #{(send(position_column).to_i).to_s}").
|
|
247
|
-
order("#{acts_as_list_class.table_name}.#{position_column} ASC").first
|
|
248
|
-
end
|
|
277
|
+
lower_items(1).first
|
|
249
278
|
end
|
|
250
279
|
|
|
251
280
|
# Return the next n lower items in the list
|
|
@@ -254,10 +283,9 @@ module ActiveRecord
|
|
|
254
283
|
limit ||= acts_as_list_list.count
|
|
255
284
|
position_value = send(position_column)
|
|
256
285
|
acts_as_list_list.
|
|
257
|
-
where("#{
|
|
258
|
-
|
|
259
|
-
limit(limit)
|
|
260
|
-
order("#{acts_as_list_class.table_name}.#{position_column} ASC")
|
|
286
|
+
where("#{quoted_position_column_with_table_name} > ?", position_value).
|
|
287
|
+
order("#{quoted_position_column_with_table_name} ASC").
|
|
288
|
+
limit(limit)
|
|
261
289
|
end
|
|
262
290
|
|
|
263
291
|
# Test if this record is in a list
|
|
@@ -284,23 +312,48 @@ module ActiveRecord
|
|
|
284
312
|
end
|
|
285
313
|
|
|
286
314
|
private
|
|
315
|
+
|
|
316
|
+
def swap_positions(item1, item2)
|
|
317
|
+
item1.set_list_position(item2.send(position_column))
|
|
318
|
+
item2.set_list_position(item1.send("#{position_column}_was"))
|
|
319
|
+
end
|
|
320
|
+
|
|
287
321
|
def acts_as_list_list
|
|
288
322
|
acts_as_list_class.unscoped do
|
|
289
323
|
acts_as_list_class.where(scope_condition)
|
|
290
324
|
end
|
|
291
325
|
end
|
|
292
326
|
|
|
327
|
+
# Poorly named methods. They will insert the item at the desired position if the position
|
|
328
|
+
# has been set manually using position=, not necessarily the top or bottom of the list:
|
|
329
|
+
|
|
293
330
|
def add_to_list_top
|
|
294
|
-
|
|
295
|
-
|
|
331
|
+
if not_in_list? || internal_scope_changed? && !position_changed || default_position?
|
|
332
|
+
increment_positions_on_all_items
|
|
333
|
+
self[position_column] = acts_as_list_top
|
|
334
|
+
else
|
|
335
|
+
increment_positions_on_lower_items(self[position_column], id)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# Make sure we know that we've processed this scope change already
|
|
339
|
+
@scope_changed = false
|
|
340
|
+
|
|
341
|
+
# Don't halt the callback chain
|
|
342
|
+
true
|
|
296
343
|
end
|
|
297
344
|
|
|
298
345
|
def add_to_list_bottom
|
|
299
|
-
if not_in_list? ||
|
|
346
|
+
if not_in_list? || internal_scope_changed? && !position_changed || default_position?
|
|
300
347
|
self[position_column] = bottom_position_in_list.to_i + 1
|
|
301
348
|
else
|
|
302
349
|
increment_positions_on_lower_items(self[position_column], id)
|
|
303
350
|
end
|
|
351
|
+
|
|
352
|
+
# Make sure we know that we've processed this scope change already
|
|
353
|
+
@scope_changed = false
|
|
354
|
+
|
|
355
|
+
# Don't halt the callback chain
|
|
356
|
+
true
|
|
304
357
|
end
|
|
305
358
|
|
|
306
359
|
# Overwrite this method to define the scope of the list changes
|
|
@@ -315,11 +368,12 @@ module ActiveRecord
|
|
|
315
368
|
|
|
316
369
|
# Returns the bottom item
|
|
317
370
|
def bottom_item(except = nil)
|
|
318
|
-
conditions =
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
371
|
+
conditions = except ? "#{quoted_table_name}.#{self.class.primary_key} != #{self.class.connection.quote(except.id)}" : {}
|
|
372
|
+
acts_as_list_list.in_list.where(
|
|
373
|
+
conditions
|
|
374
|
+
).order(
|
|
375
|
+
"#{quoted_position_column_with_table_name} DESC"
|
|
376
|
+
).first
|
|
323
377
|
end
|
|
324
378
|
|
|
325
379
|
# Forces item to assume the bottom position in the list.
|
|
@@ -334,110 +388,74 @@ module ActiveRecord
|
|
|
334
388
|
|
|
335
389
|
# This has the effect of moving all the higher items up one.
|
|
336
390
|
def decrement_positions_on_higher_items(position)
|
|
337
|
-
|
|
338
|
-
acts_as_list_class.where(scope_condition).where(
|
|
339
|
-
"#{position_column} <= #{position}"
|
|
340
|
-
).update_all(
|
|
341
|
-
"#{position_column} = (#{position_column} - 1)"
|
|
342
|
-
)
|
|
343
|
-
end
|
|
391
|
+
acts_as_list_list.where("#{quoted_position_column_with_table_name} <= ?", position).decrement_all
|
|
344
392
|
end
|
|
345
393
|
|
|
346
394
|
# This has the effect of moving all the lower items up one.
|
|
347
395
|
def decrement_positions_on_lower_items(position=nil)
|
|
348
396
|
return unless in_list?
|
|
349
397
|
position ||= send(position_column).to_i
|
|
350
|
-
|
|
351
|
-
acts_as_list_class.where(scope_condition).where(
|
|
352
|
-
"#{position_column} > #{position}"
|
|
353
|
-
).update_all(
|
|
354
|
-
"#{position_column} = (#{position_column} - 1)"
|
|
355
|
-
)
|
|
356
|
-
end
|
|
398
|
+
acts_as_list_list.where("#{quoted_position_column_with_table_name} > ?", position).decrement_all
|
|
357
399
|
end
|
|
358
400
|
|
|
359
401
|
# This has the effect of moving all the higher items down one.
|
|
360
402
|
def increment_positions_on_higher_items
|
|
361
403
|
return unless in_list?
|
|
362
|
-
|
|
363
|
-
acts_as_list_class.where(scope_condition).where(
|
|
364
|
-
"#{position_column} < #{send(position_column).to_i}"
|
|
365
|
-
).update_all(
|
|
366
|
-
"#{position_column} = (#{position_column} + 1)"
|
|
367
|
-
)
|
|
368
|
-
end
|
|
404
|
+
acts_as_list_list.where("#{quoted_position_column_with_table_name} < #{send(position_column).to_i}").increment_all
|
|
369
405
|
end
|
|
370
406
|
|
|
371
407
|
# This has the effect of moving all the lower items down one.
|
|
372
408
|
def increment_positions_on_lower_items(position, avoid_id = nil)
|
|
373
|
-
avoid_id_condition = avoid_id ? " AND #{self.class.primary_key} != #{self.class.connection.quote(avoid_id)}" : ''
|
|
409
|
+
avoid_id_condition = avoid_id ? " AND #{quoted_table_name}.#{self.class.primary_key} != #{self.class.connection.quote(avoid_id)}" : ''
|
|
374
410
|
|
|
375
|
-
|
|
376
|
-
acts_as_list_class.where(scope_condition).where(
|
|
377
|
-
"#{position_column} >= #{position}#{avoid_id_condition}"
|
|
378
|
-
).update_all(
|
|
379
|
-
"#{position_column} = (#{position_column} + 1)"
|
|
380
|
-
)
|
|
381
|
-
end
|
|
411
|
+
acts_as_list_list.where("#{quoted_position_column_with_table_name} >= #{position}#{avoid_id_condition}").increment_all
|
|
382
412
|
end
|
|
383
413
|
|
|
384
414
|
# Increments position (<tt>position_column</tt>) of all items in the list.
|
|
385
415
|
def increment_positions_on_all_items
|
|
386
|
-
|
|
387
|
-
acts_as_list_class.where(
|
|
388
|
-
scope_condition
|
|
389
|
-
).update_all(
|
|
390
|
-
"#{position_column} = (#{position_column} + 1)"
|
|
391
|
-
)
|
|
392
|
-
end
|
|
416
|
+
acts_as_list_list.increment_all
|
|
393
417
|
end
|
|
394
418
|
|
|
395
419
|
# Reorders intermediate items to support moving an item from old_position to new_position.
|
|
396
420
|
def shuffle_positions_on_intermediate_items(old_position, new_position, avoid_id = nil)
|
|
397
421
|
return if old_position == new_position
|
|
398
|
-
avoid_id_condition = avoid_id ? " AND #{self.class.primary_key} != #{self.class.connection.quote(avoid_id)}" : ''
|
|
422
|
+
avoid_id_condition = avoid_id ? " AND #{quoted_table_name}.#{self.class.primary_key} != #{self.class.connection.quote(avoid_id)}" : ''
|
|
399
423
|
|
|
400
424
|
if old_position < new_position
|
|
401
425
|
# Decrement position of intermediate items
|
|
402
426
|
#
|
|
403
427
|
# e.g., if moving an item from 2 to 5,
|
|
404
428
|
# move [3, 4, 5] to [2, 3, 4]
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
).update_all(
|
|
411
|
-
"#{position_column} = (#{position_column} - 1)"
|
|
412
|
-
)
|
|
413
|
-
end
|
|
429
|
+
acts_as_list_list.where(
|
|
430
|
+
"#{quoted_position_column_with_table_name} > ?", old_position
|
|
431
|
+
).where(
|
|
432
|
+
"#{quoted_position_column_with_table_name} <= #{new_position}#{avoid_id_condition}"
|
|
433
|
+
).decrement_all
|
|
414
434
|
else
|
|
415
435
|
# Increment position of intermediate items
|
|
416
436
|
#
|
|
417
437
|
# e.g., if moving an item from 5 to 2,
|
|
418
438
|
# move [2, 3, 4] to [3, 4, 5]
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
).update_all(
|
|
425
|
-
"#{position_column} = (#{position_column} + 1)"
|
|
426
|
-
)
|
|
427
|
-
end
|
|
439
|
+
acts_as_list_list.where(
|
|
440
|
+
"#{quoted_position_column_with_table_name} >= ?", new_position
|
|
441
|
+
).where(
|
|
442
|
+
"#{quoted_position_column_with_table_name} < #{old_position}#{avoid_id_condition}"
|
|
443
|
+
).increment_all
|
|
428
444
|
end
|
|
429
445
|
end
|
|
430
446
|
|
|
431
447
|
def insert_at_position(position)
|
|
432
448
|
return set_list_position(position) if new_record?
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
449
|
+
with_lock do
|
|
450
|
+
if in_list?
|
|
451
|
+
old_position = send(position_column).to_i
|
|
452
|
+
return if position == old_position
|
|
453
|
+
shuffle_positions_on_intermediate_items(old_position, position)
|
|
454
|
+
else
|
|
455
|
+
increment_positions_on_lower_items(position)
|
|
456
|
+
end
|
|
457
|
+
set_list_position(position)
|
|
439
458
|
end
|
|
440
|
-
set_list_position(position)
|
|
441
459
|
end
|
|
442
460
|
|
|
443
461
|
# used by insert_at_position instead of remove_from_list, as postgresql raises error if position_column has non-null constraint
|
|
@@ -453,29 +471,32 @@ module ActiveRecord
|
|
|
453
471
|
old_position = send("#{position_column}_was").to_i
|
|
454
472
|
new_position = send(position_column).to_i
|
|
455
473
|
|
|
456
|
-
return unless
|
|
457
|
-
|
|
458
|
-
|
|
474
|
+
return unless acts_as_list_list.where(
|
|
475
|
+
"#{quoted_position_column_with_table_name} = #{new_position}"
|
|
476
|
+
).count > 1
|
|
459
477
|
shuffle_positions_on_intermediate_items old_position, new_position, id
|
|
460
478
|
end
|
|
461
479
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
480
|
+
def internal_scope_changed?
|
|
481
|
+
return @scope_changed if defined?(@scope_changed)
|
|
482
|
+
|
|
483
|
+
@scope_changed = scope_changed?
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
def clear_scope_changed
|
|
487
|
+
remove_instance_variable(:@scope_changed) if defined?(@scope_changed)
|
|
466
488
|
end
|
|
467
489
|
|
|
468
490
|
def check_scope
|
|
469
|
-
if
|
|
470
|
-
|
|
491
|
+
if internal_scope_changed?
|
|
492
|
+
cached_changes = changes
|
|
493
|
+
|
|
494
|
+
cached_changes.each { |attribute, values| self[attribute] = values[0] }
|
|
471
495
|
send('decrement_positions_on_lower_items') if lower_item
|
|
472
|
-
|
|
473
|
-
send("add_to_list_#{add_new_at}")
|
|
474
|
-
end
|
|
475
|
-
end
|
|
496
|
+
cached_changes.each { |attribute, values| self[attribute] = values[1] }
|
|
476
497
|
|
|
477
|
-
|
|
478
|
-
|
|
498
|
+
send("add_to_list_#{add_new_at}") if add_new_at.present?
|
|
499
|
+
end
|
|
479
500
|
end
|
|
480
501
|
|
|
481
502
|
# This check is skipped if the position is currently the default position from the table
|
|
@@ -485,6 +506,20 @@ module ActiveRecord
|
|
|
485
506
|
self[position_column] = acts_as_list_top
|
|
486
507
|
end
|
|
487
508
|
end
|
|
509
|
+
|
|
510
|
+
# When using raw column name it must be quoted otherwise it can raise syntax errors with SQL keywords (e.g. order)
|
|
511
|
+
def quoted_position_column
|
|
512
|
+
@_quoted_position_column ||= self.class.connection.quote_column_name(position_column)
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
# Used in order clauses
|
|
516
|
+
def quoted_table_name
|
|
517
|
+
@_quoted_table_name ||= acts_as_list_class.quoted_table_name
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
def quoted_position_column_with_table_name
|
|
521
|
+
@_quoted_position_column_with_table_name ||= "#{quoted_table_name}.#{quoted_position_column}"
|
|
522
|
+
end
|
|
488
523
|
end
|
|
489
524
|
end
|
|
490
525
|
end
|
data/lib/acts_as_list/version.rb
CHANGED
data/test/helper.rb
CHANGED
|
@@ -11,4 +11,11 @@ require "active_record"
|
|
|
11
11
|
require "minitest/autorun"
|
|
12
12
|
require "#{File.dirname(__FILE__)}/../init"
|
|
13
13
|
|
|
14
|
+
if defined?(ActiveRecord::VERSION) &&
|
|
15
|
+
ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR >= 2
|
|
16
|
+
|
|
17
|
+
# Was removed in Rails 5 and is effectively true.
|
|
18
|
+
ActiveRecord::Base.raise_in_transactional_callbacks = true
|
|
19
|
+
end
|
|
20
|
+
|
|
14
21
|
require "shared"
|
data/test/shared.rb
CHANGED
data/test/shared_list.rb
CHANGED
|
@@ -104,6 +104,12 @@ module Shared
|
|
|
104
104
|
|
|
105
105
|
new4.reload
|
|
106
106
|
assert_equal 5, new4.pos
|
|
107
|
+
|
|
108
|
+
last1 = ListMixin.order('pos').last
|
|
109
|
+
last2 = ListMixin.order('pos').last
|
|
110
|
+
last1.insert_at(1)
|
|
111
|
+
last2.insert_at(1)
|
|
112
|
+
assert_equal [1, 2, 3, 4, 5], ListMixin.where(parent_id: 20).order('pos').map(&:pos)
|
|
107
113
|
end
|
|
108
114
|
|
|
109
115
|
def test_delete_middle
|
|
@@ -142,7 +148,7 @@ module Shared
|
|
|
142
148
|
|
|
143
149
|
def test_update_position_when_scope_changes
|
|
144
150
|
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
|
|
145
|
-
|
|
151
|
+
ListMixin.create(parent_id: 6)
|
|
146
152
|
|
|
147
153
|
ListMixin.where(id: 2).first.move_within_scope(6)
|
|
148
154
|
|
|
@@ -246,5 +252,11 @@ module Shared
|
|
|
246
252
|
|
|
247
253
|
assert_equal [5, 1, 6, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
|
|
248
254
|
end
|
|
255
|
+
|
|
256
|
+
def test_non_persisted_records_dont_get_lock_called
|
|
257
|
+
new = ListMixin.new(parent_id: 5)
|
|
258
|
+
|
|
259
|
+
new.destroy
|
|
260
|
+
end
|
|
249
261
|
end
|
|
250
262
|
end
|
data/test/shared_list_sub.rb
CHANGED
|
@@ -43,6 +43,32 @@ module Shared
|
|
|
43
43
|
assert_nil ListMixin.where(id: 4).first.lower_item
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
def test_next_prev_not_regular_sequence
|
|
47
|
+
ListMixin.all.each do |item|
|
|
48
|
+
item.update_attributes(pos: item.pos * 5)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
|
|
52
|
+
|
|
53
|
+
ListMixin.where(id: 2).first.move_lower
|
|
54
|
+
assert_equal [1, 3, 2, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
|
|
55
|
+
|
|
56
|
+
ListMixin.where(id: 2).first.move_higher
|
|
57
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
|
|
58
|
+
|
|
59
|
+
ListMixin.where(id: 1).first.move_to_bottom
|
|
60
|
+
assert_equal [2, 3, 4, 1], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
|
|
61
|
+
|
|
62
|
+
ListMixin.where(id: 1).first.move_to_top
|
|
63
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
|
|
64
|
+
|
|
65
|
+
ListMixin.where(id: 2).first.move_to_bottom
|
|
66
|
+
assert_equal [1, 3, 4, 2], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
|
|
67
|
+
|
|
68
|
+
ListMixin.where(id: 4).first.move_to_top
|
|
69
|
+
assert_equal [4, 1, 3, 2], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
|
|
70
|
+
end
|
|
71
|
+
|
|
46
72
|
def test_next_prev_groups
|
|
47
73
|
li1 = ListMixin.where(id: 1).first
|
|
48
74
|
li2 = ListMixin.where(id: 2).first
|
|
@@ -53,9 +79,9 @@ module Shared
|
|
|
53
79
|
assert_equal [li2, li3], li1.lower_items(2)
|
|
54
80
|
assert_equal [], li4.lower_items
|
|
55
81
|
|
|
56
|
-
assert_equal [
|
|
82
|
+
assert_equal [li2, li1], li3.higher_items
|
|
57
83
|
assert_equal [li1], li2.higher_items
|
|
58
|
-
assert_equal [
|
|
84
|
+
assert_equal [li3, li2], li4.higher_items(2)
|
|
59
85
|
assert_equal [], li1.higher_items
|
|
60
86
|
end
|
|
61
87
|
|
data/test/shared_no_addition.rb
CHANGED
|
@@ -21,5 +21,16 @@ module Shared
|
|
|
21
21
|
assert !new.in_list?
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
def test_update_scope_does_not_add_to_list
|
|
25
|
+
new = NoAdditionMixin.create
|
|
26
|
+
|
|
27
|
+
new.update_attribute(:parent_id, 20)
|
|
28
|
+
new.reload
|
|
29
|
+
assert !new.in_list?
|
|
30
|
+
|
|
31
|
+
new.update_attribute(:parent_id, 5)
|
|
32
|
+
new.reload
|
|
33
|
+
assert !new.in_list?
|
|
34
|
+
end
|
|
24
35
|
end
|
|
25
36
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Shared
|
|
2
|
+
module Quoting
|
|
3
|
+
|
|
4
|
+
def setup
|
|
5
|
+
3.times { |counter| QuotedList.create! order: counter }
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def test_create
|
|
9
|
+
assert_equal QuotedList.in_list.size, 3
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# This test execute raw queries involving table name
|
|
13
|
+
def test_moving
|
|
14
|
+
item = QuotedList.first
|
|
15
|
+
item.higher_items
|
|
16
|
+
item.lower_items
|
|
17
|
+
item.send :bottom_item # Part of private api
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
end
|