acts_as_list 0.4.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d5cbf688ac985c43f61b4c0669030f5b6f6c6caa
4
- data.tar.gz: aef8fc0d40ed0ee55bf73ff2b7989e14e9c6572e
3
+ metadata.gz: 0cf6c26261c5ef1690443023c346ddf8de5f5a95
4
+ data.tar.gz: 419d7210f9a06bd54a113da0b8e8c929f716f4b6
5
5
  SHA512:
6
- metadata.gz: de7f8dd3123cb1bf1fd5837517c221d8a6682207c3a75ac99a7457782b5ebf6d3fa995ee12664674cc7dfacaca6bd7e5ffaa484407502856aa8e9932ff066746
7
- data.tar.gz: 20d069cc6a4420dd3dd6073f12ab8940cf2bb3c1003bd71faca489ddefe780349159696cd12ef37e65578ac796c0d4686af3c231cff832f3eb2b2a3306f2da62
6
+ metadata.gz: 07d0a625d3d0ea4344b4fea41be748b0191a0495edd5255e679c3c543b3101e70711f47595f5f6009f2490f01cf7c8e5683370254a65d654bed00ec7e6eb5265
7
+ data.tar.gz: aaea3b5d86259b0564ea278a7dc936b2826b82a66d6c25e8abc33cb9124d434fb4a57de70c01751176ef285d8d36a25f8b62b9b60e18a6dcf198713fbe5cd2d6
@@ -5,7 +5,7 @@ rvm:
5
5
  - 2.0.0
6
6
  - 2.1.0
7
7
  - jruby-19mode
8
- - rbx
8
+ - rbx-2
9
9
  gemfile:
10
10
  - gemfiles/rails3/Gemfile
11
11
  - gemfiles/rails4/Gemfile
data/Gemfile CHANGED
@@ -12,4 +12,8 @@ end
12
12
  # Specify your gem's dependencies in acts_as_list-rails3.gemspec
13
13
  gemspec
14
14
 
15
- gem 'rake'
15
+ gem 'rake'
16
+
17
+ group :test do
18
+ gem 'minitest', '~> 5'
19
+ end
data/README.md CHANGED
@@ -76,6 +76,15 @@ All `position` queries (select, update, etc.) inside gem methods are executed wi
76
76
 
77
77
  The `position` column is set after validations are called, so you should not put a `presence` validation on the `position` column.
78
78
 
79
+
80
+ If you need a scope by a non-association field you should pass an array, containing field name, to a scope:
81
+ ```ruby
82
+ class TodoItem < ActiveRecord::Base
83
+ # `kind` is a plain text field (e.g. 'work', 'shopping', 'meeting'), not an association
84
+ acts_as_list scope: [:kind]
85
+ end
86
+ ```
87
+
79
88
  ## Versions
80
89
  All versions `0.1.5` onwards require Rails 3.0.x and higher.
81
90
 
@@ -15,3 +15,7 @@ gem 'activerecord', '>= 3.0', '< 4'
15
15
  gemspec :path => File.join('..', '..')
16
16
 
17
17
  gem 'rake'
18
+
19
+ group :test do
20
+ gem 'minitest', '~> 5'
21
+ end
@@ -9,10 +9,13 @@ platforms :rbx do
9
9
  gem 'rubysl-test-unit'
10
10
  end
11
11
 
12
-
13
12
  gem 'activerecord', '>= 4.0.0', '< 5'
14
13
 
15
14
  # Specify your gem's dependencies in acts_as_list.gemspec
16
15
  gemspec :path => File.join('..', '..')
17
16
 
18
17
  gem 'rake'
18
+
19
+ group :test do
20
+ gem 'minitest', '~> 5'
21
+ end
data/init.rb CHANGED
@@ -1,4 +1,2 @@
1
1
  $:.unshift "#{File.dirname(__FILE__)}/lib"
2
2
  require 'acts_as_list'
3
-
4
- ActsAsList::Railtie.insert
@@ -1,24 +1,17 @@
1
1
  require 'acts_as_list/active_record/acts/list'
2
2
 
3
3
  module ActsAsList
4
- if defined? Rails::Railtie
4
+ begin
5
5
  require 'rails'
6
+
6
7
  class Railtie < Rails::Railtie
7
8
  initializer 'acts_as_list.insert_into_active_record' do
8
9
  ActiveSupport.on_load :active_record do
9
- ActsAsList::Railtie.insert
10
+ ActiveRecord::Base.send(:include, ActiveRecord::Acts::List)
10
11
  end
11
12
  end
12
13
  end
13
- end
14
-
15
- class Railtie
16
- def self.insert
17
- if defined?(ActiveRecord)
18
- ActiveRecord::Base.send(:include, ActiveRecord::Acts::List)
19
- end
20
- end
14
+ rescue LoadError
15
+ ActiveRecord::Base.send(:include, ActiveRecord::Acts::List) if defined?(ActiveRecord)
21
16
  end
22
17
  end
23
-
24
- ActsAsList::Railtie.insert
@@ -99,6 +99,11 @@ module ActiveRecord
99
99
  '#{configuration[:add_new_at]}'
100
100
  end
101
101
 
102
+ def #{configuration[:column]}=(position)
103
+ write_attribute(:#{configuration[:column]}, position)
104
+ @position_changed = true
105
+ end
106
+
102
107
  #{scope_methods}
103
108
 
104
109
  # only add to attr_accessible
@@ -182,7 +187,8 @@ module ActiveRecord
182
187
  end
183
188
  end
184
189
 
185
- # Move the item within scope
190
+ # Move the item within scope. If a position within the new scope isn't supplied, the item will
191
+ # be appended to the end of the list.
186
192
  def move_within_scope(scope_id)
187
193
  send("#{scope_name}=", scope_id)
188
194
  save!
@@ -215,9 +221,10 @@ module ActiveRecord
215
221
  # Return the next higher item in the list.
216
222
  def higher_item
217
223
  return nil unless in_list?
218
- acts_as_list_class.unscoped.
219
- where("#{scope_condition} AND #{position_column} < #{(send(position_column).to_i).to_s}").
224
+ acts_as_list_class.unscoped do
225
+ acts_as_list_class.where("#{scope_condition} AND #{position_column} < #{(send(position_column).to_i).to_s}").
220
226
  order("#{acts_as_list_class.table_name}.#{position_column} DESC").first
227
+ end
221
228
  end
222
229
 
223
230
  # Return the next n higher items in the list
@@ -235,9 +242,10 @@ module ActiveRecord
235
242
  # Return the next lower item in the list.
236
243
  def lower_item
237
244
  return nil unless in_list?
238
- acts_as_list_class.unscoped.
239
- where("#{scope_condition} AND #{position_column} > #{(send(position_column).to_i).to_s}").
245
+ acts_as_list_class.unscoped do
246
+ acts_as_list_class.where("#{scope_condition} AND #{position_column} > #{(send(position_column).to_i).to_s}").
240
247
  order("#{acts_as_list_class.table_name}.#{position_column} ASC").first
248
+ end
241
249
  end
242
250
 
243
251
  # Return the next n lower items in the list
@@ -266,19 +274,20 @@ module ActiveRecord
266
274
  end
267
275
 
268
276
  def default_position?
269
- default_position == send(position_column)
277
+ default_position && default_position.to_i == send(position_column)
270
278
  end
271
279
 
272
280
  # Sets the new position and saves it
273
281
  def set_list_position(new_position)
274
- send("#{position_column}=", new_position)
275
- save!
282
+ write_attribute position_column, new_position
283
+ save(validate: false)
276
284
  end
277
285
 
278
286
  private
279
287
  def acts_as_list_list
280
- acts_as_list_class.unscoped.
281
- where(scope_condition)
288
+ acts_as_list_class.unscoped do
289
+ acts_as_list_class.where(scope_condition)
290
+ end
282
291
  end
283
292
 
284
293
  def add_to_list_top
@@ -287,10 +296,10 @@ module ActiveRecord
287
296
  end
288
297
 
289
298
  def add_to_list_bottom
290
- if not_in_list? || default_position?
299
+ if not_in_list? || scope_changed? && !@position_changed || default_position?
291
300
  self[position_column] = bottom_position_in_list.to_i + 1
292
301
  else
293
- increment_positions_on_lower_items(self[position_column])
302
+ increment_positions_on_lower_items(self[position_column], id)
294
303
  end
295
304
  end
296
305
 
@@ -307,8 +316,10 @@ module ActiveRecord
307
316
  # Returns the bottom item
308
317
  def bottom_item(except = nil)
309
318
  conditions = scope_condition
310
- conditions = "#{conditions} AND #{self.class.primary_key} != '#{except.id}'" if except
311
- acts_as_list_class.unscoped.in_list.where(conditions).order("#{acts_as_list_class.table_name}.#{position_column} DESC").first
319
+ conditions = "#{conditions} AND #{self.class.primary_key} != #{self.class.connection.quote(except.id)}" if except
320
+ acts_as_list_class.unscoped do
321
+ acts_as_list_class.in_list.where(conditions).order("#{acts_as_list_class.table_name}.#{position_column} DESC").first
322
+ end
312
323
  end
313
324
 
314
325
  # Forces item to assume the bottom position in the list.
@@ -323,76 +334,93 @@ module ActiveRecord
323
334
 
324
335
  # This has the effect of moving all the higher items up one.
325
336
  def decrement_positions_on_higher_items(position)
326
- acts_as_list_class.unscoped.where(
327
- "#{scope_condition} AND #{position_column} <= #{position}"
328
- ).update_all(
329
- "#{position_column} = (#{position_column} - 1)"
330
- )
337
+ acts_as_list_class.unscoped do
338
+ acts_as_list_class.where(
339
+ "#{scope_condition} AND #{position_column} <= #{position}"
340
+ ).update_all(
341
+ "#{position_column} = (#{position_column} - 1)"
342
+ )
343
+ end
331
344
  end
332
345
 
333
346
  # This has the effect of moving all the lower items up one.
334
347
  def decrement_positions_on_lower_items(position=nil)
335
348
  return unless in_list?
336
349
  position ||= send(position_column).to_i
337
- acts_as_list_class.unscoped.where(
338
- "#{scope_condition} AND #{position_column} > #{position}"
339
- ).update_all(
340
- "#{position_column} = (#{position_column} - 1)"
341
- )
350
+ acts_as_list_class.unscoped do
351
+ acts_as_list_class.where(
352
+ "#{scope_condition} AND #{position_column} > #{position}"
353
+ ).update_all(
354
+ "#{position_column} = (#{position_column} - 1)"
355
+ )
356
+ end
342
357
  end
343
358
 
344
359
  # This has the effect of moving all the higher items down one.
345
360
  def increment_positions_on_higher_items
346
361
  return unless in_list?
347
- acts_as_list_class.unscoped.where(
348
- "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}"
349
- ).update_all(
350
- "#{position_column} = (#{position_column} + 1)"
351
- )
362
+ acts_as_list_class.unscoped do
363
+ acts_as_list_class.where(
364
+ "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}"
365
+ ).update_all(
366
+ "#{position_column} = (#{position_column} + 1)"
367
+ )
368
+ end
352
369
  end
353
370
 
354
371
  # This has the effect of moving all the lower items down one.
355
- def increment_positions_on_lower_items(position)
356
- acts_as_list_class.unscoped.where(
357
- "#{scope_condition} AND #{position_column} >= #{position}"
358
- ).update_all(
359
- "#{position_column} = (#{position_column} + 1)"
360
- )
372
+ 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)}" : ''
374
+
375
+ acts_as_list_class.unscoped do
376
+ acts_as_list_class.where(
377
+ "#{scope_condition} AND #{position_column} >= #{position}#{avoid_id_condition}"
378
+ ).update_all(
379
+ "#{position_column} = (#{position_column} + 1)"
380
+ )
381
+ end
361
382
  end
362
383
 
363
384
  # Increments position (<tt>position_column</tt>) of all items in the list.
364
385
  def increment_positions_on_all_items
365
- acts_as_list_class.unscoped.where(
366
- "#{scope_condition}"
367
- ).update_all(
368
- "#{position_column} = (#{position_column} + 1)"
369
- )
386
+ acts_as_list_class.unscoped do
387
+ acts_as_list_class.where(
388
+ "#{scope_condition}"
389
+ ).update_all(
390
+ "#{position_column} = (#{position_column} + 1)"
391
+ )
392
+ end
370
393
  end
371
394
 
372
395
  # Reorders intermediate items to support moving an item from old_position to new_position.
373
396
  def shuffle_positions_on_intermediate_items(old_position, new_position, avoid_id = nil)
374
397
  return if old_position == new_position
375
- avoid_id_condition = avoid_id ? " AND #{self.class.primary_key} != '#{avoid_id}'" : ''
398
+ avoid_id_condition = avoid_id ? " AND #{self.class.primary_key} != #{self.class.connection.quote(avoid_id)}" : ''
399
+
376
400
  if old_position < new_position
377
401
  # Decrement position of intermediate items
378
402
  #
379
403
  # e.g., if moving an item from 2 to 5,
380
404
  # move [3, 4, 5] to [2, 3, 4]
381
- acts_as_list_class.unscoped.where(
382
- "#{scope_condition} AND #{position_column} > #{old_position} AND #{position_column} <= #{new_position}#{avoid_id_condition}"
383
- ).update_all(
384
- "#{position_column} = (#{position_column} - 1)"
385
- )
405
+ acts_as_list_class.unscoped do
406
+ acts_as_list_class.where(
407
+ "#{scope_condition} AND #{position_column} > #{old_position} AND #{position_column} <= #{new_position}#{avoid_id_condition}"
408
+ ).update_all(
409
+ "#{position_column} = (#{position_column} - 1)"
410
+ )
411
+ end
386
412
  else
387
413
  # Increment position of intermediate items
388
414
  #
389
415
  # e.g., if moving an item from 5 to 2,
390
416
  # move [2, 3, 4] to [3, 4, 5]
391
- acts_as_list_class.unscoped.where(
392
- "#{scope_condition} AND #{position_column} >= #{new_position} AND #{position_column} < #{old_position}#{avoid_id_condition}"
393
- ).update_all(
394
- "#{position_column} = (#{position_column} + 1)"
395
- )
417
+ acts_as_list_class.unscoped do
418
+ acts_as_list_class.where(
419
+ "#{scope_condition} AND #{position_column} >= #{new_position} AND #{position_column} < #{old_position}#{avoid_id_condition}"
420
+ ).update_all(
421
+ "#{position_column} = (#{position_column} + 1)"
422
+ )
423
+ end
396
424
  end
397
425
  end
398
426
 
@@ -421,7 +449,9 @@ module ActiveRecord
421
449
  old_position = send("#{position_column}_was").to_i
422
450
  new_position = send(position_column).to_i
423
451
 
424
- return unless acts_as_list_class.unscoped.where("#{scope_condition} AND #{position_column} = #{new_position}").count > 1
452
+ return unless acts_as_list_class.unscoped do
453
+ acts_as_list_class.where("#{scope_condition} AND #{position_column} = #{new_position}").count > 1
454
+ end
425
455
  shuffle_positions_on_intermediate_items old_position, new_position, id
426
456
  end
427
457
 
@@ -444,8 +474,10 @@ module ActiveRecord
444
474
  self.reload
445
475
  end
446
476
 
477
+ # This check is skipped if the position is currently the default position from the table
478
+ # as modifying the default position on creation is handled elsewhere
447
479
  def check_top_position
448
- if send(position_column) && send(position_column) < acts_as_list_top
480
+ if send(position_column) && !default_position? && send(position_column) < acts_as_list_top
449
481
  self[position_column] = acts_as_list_top
450
482
  end
451
483
  end
@@ -1,7 +1,7 @@
1
1
  module ActiveRecord
2
2
  module Acts
3
3
  module List
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'
5
5
  end
6
6
  end
7
7
  end
@@ -137,12 +137,12 @@ module Shared
137
137
  def test_nil_scope
138
138
  new1, new2, new3 = ListMixin.create, ListMixin.create, ListMixin.create
139
139
  new2.move_higher
140
- assert_equal [new2, new1, new3], ListMixin.where(parent_id: nil).order('pos')
140
+ assert_equal [new2, new1, new3].map(&:id), ListMixin.where(parent_id: nil).order('pos').map(&:id)
141
141
  end
142
142
 
143
143
  def test_update_position_when_scope_changes
144
144
  assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
145
- parent = ListMixin.create(id: 6)
145
+ parent = ListMixin.create(parent_id: 6)
146
146
 
147
147
  ListMixin.where(id: 2).first.move_within_scope(6)
148
148
 
@@ -155,7 +155,7 @@ module Shared
155
155
  assert_equal 3, ListMixin.where(id: 4).first.pos
156
156
 
157
157
  ListMixin.where(id: 2).first.move_within_scope(5)
158
- assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
158
+ assert_equal [1, 3, 4, 2], ListMixin.where(parent_id: 5).order('pos').map(&:id)
159
159
  end
160
160
 
161
161
  def test_remove_from_list_should_then_fail_in_list?
@@ -6,16 +6,21 @@ ActiveRecord::Schema.verbose = false
6
6
 
7
7
  def setup_db(position_options = {})
8
8
  # AR caches columns options like defaults etc. Clear them!
9
+ ActiveRecord::Base.connection.create_table :mixins do |t|
10
+ t.column :pos, :integer, position_options
11
+ t.column :active, :boolean, default: true
12
+ t.column :parent_id, :integer
13
+ t.column :parent_type, :string
14
+ t.column :created_at, :datetime
15
+ t.column :updated_at, :datetime
16
+ end
17
+
9
18
  ActiveRecord::Base.connection.schema_cache.clear!
10
- ActiveRecord::Schema.define(version: 1) do
11
- create_table :mixins do |t|
12
- t.column :pos, :integer, position_options
13
- t.column :active, :boolean, default: true
14
- t.column :parent_id, :integer
15
- t.column :parent_type, :string
16
- t.column :created_at, :datetime
17
- t.column :updated_at, :datetime
18
- end
19
+ [ Mixin, ListMixin, ListMixinSub1, ListMixinSub2, ListWithStringScopeMixin,
20
+ ArrayScopeListMixin, ZeroBasedMixin, DefaultScopedMixin,
21
+ DefaultScopedWhereMixin, TopAdditionMixin, NoAdditionMixin ].each do |klass|
22
+
23
+ klass.reset_column_information
19
24
  end
20
25
  end
21
26
 
@@ -87,8 +92,8 @@ class NoAdditionMixin < Mixin
87
92
  acts_as_list column: "pos", add_new_at: nil, scope: :parent_id
88
93
  end
89
94
 
90
- class ActsAsListTestCase < MiniTest::Unit::TestCase
91
- # No default test required a this class is abstract.
95
+ class ActsAsListTestCase < Minitest::Test
96
+ # No default test required as this class is abstract.
92
97
  # Need for test/unit.
93
98
  undef_method :default_test if method_defined?(:default_test)
94
99
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_list
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-02-22 00:00:00.000000000 Z
13
+ date: 2014-10-31 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -92,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
92
  version: '0'
93
93
  requirements: []
94
94
  rubyforge_project: acts_as_list
95
- rubygems_version: 2.2.2
95
+ rubygems_version: 2.0.14
96
96
  signing_key:
97
97
  specification_version: 4
98
98
  summary: A gem allowing a active_record model to act_as_list.