acts_as_list 0.9.5 → 0.9.6

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: 66daa5cd56691f7a638ae9dd8f1a9c3feec0577c
4
- data.tar.gz: 7574120085bc23b698489eeb890112df78dd7689
3
+ metadata.gz: 5be2da067217f4dab82cf86a51c149578b3839ff
4
+ data.tar.gz: ead2d7fc41857aa193f37d0f8cbd5bffbe052462
5
5
  SHA512:
6
- metadata.gz: acad50db58bda1347963b54c71929bf9d79fce33e47b3efc0c3d7f2ffe17a370ff984c3ff83796e3a31350ec10fce07d2448d95adf796cf1661166070f06ada6
7
- data.tar.gz: 7d3bdb848e5a1bc50ed1b5e620eaaaa940cb956a23f1fc12649ca1fab410a2dd3d9df8e0190fd6229ec69048c0066fad59d86d5f48ef07b8e2602d3b1bcf4ee8
6
+ metadata.gz: fa9338e297f70fc50afd3d1ad6bf4d933883f0626f6f85a2ef79543255a4191df222a90e9b683edc95d3f613f27135538de0dc795086144e7d6bcbc4404c87a9
7
+ data.tar.gz: 02f13a0c906e75a3fe32341bcaa6237c3ba4ba258bbf80809a7cc332dffb0e1d90e3ab1047335ad46f6f315a3daf2b46dadc44959d791009617588d849f99988
@@ -1,5 +1,18 @@
1
1
  # Change Log
2
2
 
3
+ ## [v0.9.5](https://github.com/swanandp/acts_as_list/tree/v0.9.5) (2017-04-04)
4
+ [Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.4...v0.9.5)
5
+
6
+ **Closed issues:**
7
+
8
+ - acts\_as\_list\_class.maximum\(position\_column\) is causing the entire table to lock [\#264](https://github.com/swanandp/acts_as_list/issues/264)
9
+ - Be more precise with unscope-ing [\#263](https://github.com/swanandp/acts_as_list/issues/263)
10
+
11
+ **Merged pull requests:**
12
+
13
+ - Use bottom\_position\_in\_list instead of the highest value in the table [\#266](https://github.com/swanandp/acts_as_list/pull/266) ([brendon](https://github.com/brendon))
14
+ - Be more surgical about unscoping [\#265](https://github.com/swanandp/acts_as_list/pull/265) ([brendon](https://github.com/brendon))
15
+
3
16
  ## [v0.9.4](https://github.com/swanandp/acts_as_list/tree/v0.9.4) (2017-03-16)
4
17
  [Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.3...v0.9.4)
5
18
 
@@ -24,6 +24,6 @@ Gem::Specification.new do |s|
24
24
 
25
25
 
26
26
  # Dependencies (installed via "bundle install")
27
- s.add_dependency("activerecord", [">= 3.0"])
28
- s.add_development_dependency("bundler", [">= 1.0.0"])
27
+ s.add_dependency "activerecord", ">= 3.0"
28
+ s.add_development_dependency "bundler", ">= 1.0.0"
29
29
  end
@@ -1,9 +1,10 @@
1
- require 'acts_as_list/active_record/acts/list'
1
+ require "acts_as_list/active_record/acts/list"
2
2
  require "acts_as_list/active_record/acts/position_column_method_definer"
3
3
  require "acts_as_list/active_record/acts/scope_method_definer"
4
4
  require "acts_as_list/active_record/acts/top_of_list_method_definer"
5
5
  require "acts_as_list/active_record/acts/add_new_at_method_definer"
6
6
  require "acts_as_list/active_record/acts/aux_method_definer"
7
7
  require "acts_as_list/active_record/acts/callback_definer"
8
- require 'acts_as_list/active_record/acts/no_update'
8
+ require "acts_as_list/active_record/acts/no_update"
9
9
  require "acts_as_list/active_record/acts/sequential_updates_method_definer"
10
+ require "acts_as_list/active_record/acts/active_record"
@@ -0,0 +1,3 @@
1
+ ActiveSupport.on_load :active_record do
2
+ extend ActiveRecord::Acts::List::ClassMethods
3
+ end
@@ -1,64 +1,66 @@
1
- class << ActiveRecord::Base
2
- # Configuration options are:
3
- #
4
- # * +column+ - specifies the column name to use for keeping the position integer (default: +position+)
5
- # * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach <tt>_id</tt>
6
- # (if it hasn't already been added) and use that as the foreign key restriction. It's also possible
7
- # to give it an entire string that is interpolated if you need a tighter scope than just a foreign key.
8
- # Example: <tt>acts_as_list scope: 'todo_list_id = #{todo_list_id} AND completed = 0'</tt>
9
- # * +top_of_list+ - defines the integer used for the top of the list. Defaults to 1. Use 0 to make the collection
10
- # act more like an array in its indexing.
11
- # * +add_new_at+ - specifies whether objects get added to the :top or :bottom of the list. (default: +bottom+)
12
- # `nil` will result in new items not being added to the list on create.
13
- # * +sequential_updates+ - specifies whether insert_at should update objects positions during shuffling
14
- # one by one to respect position column unique not null constraint.
15
- # Defaults to true if position column has unique index, otherwise false.
16
- # If constraint is <tt>deferrable initially deferred<tt>, overriding it with false will speed up insert_at.
17
- def acts_as_list(options = {})
18
- configuration = { column: "position", scope: "1 = 1", top_of_list: 1, add_new_at: :bottom }
19
- configuration.update(options) if options.is_a?(Hash)
20
-
21
- caller_class = self
22
-
23
- ActiveRecord::Acts::List::PositionColumnMethodDefiner.call(caller_class, configuration[:column])
24
- ActiveRecord::Acts::List::ScopeMethodDefiner.call(caller_class, configuration[:scope])
25
- ActiveRecord::Acts::List::TopOfListMethodDefiner.call(caller_class, configuration[:top_of_list])
26
- ActiveRecord::Acts::List::AddNewAtMethodDefiner.call(caller_class, configuration[:add_new_at])
27
-
28
- ActiveRecord::Acts::List::AuxMethodDefiner.call(caller_class)
29
- ActiveRecord::Acts::List::CallbackDefiner.call(caller_class, configuration[:add_new_at])
30
- ActiveRecord::Acts::List::SequentialUpdatesMethodDefiner.call(caller_class, configuration[:column], configuration[:sequential_updates])
31
-
32
- include ActiveRecord::Acts::List::InstanceMethods
33
- include ActiveRecord::Acts::List::NoUpdate
34
- end
35
- end
36
-
37
1
  module ActiveRecord
38
2
  module Acts #:nodoc:
39
3
  module List #:nodoc:
40
- # This +acts_as+ extension provides the capabilities for sorting and reordering a number of objects in a list.
41
- # The class that has this specified needs to have a +position+ column defined as an integer on
42
- # the mapped database table.
43
- #
44
- # Todo list example:
45
- #
46
- # class TodoList < ActiveRecord::Base
47
- # has_many :todo_items, order: "position"
48
- # end
49
- #
50
- # class TodoItem < ActiveRecord::Base
51
- # belongs_to :todo_list
52
- # acts_as_list scope: :todo_list
53
- # end
54
- #
55
- # todo_list.first.move_to_bottom
56
- # todo_list.last.move_higher
57
-
58
- # All the methods available to a record that has had <tt>acts_as_list</tt> specified. Each method works
59
- # by assuming the object to be the item in the list, so <tt>chapter.move_lower</tt> would move that chapter
60
- # lower in the list of all chapters. Likewise, <tt>chapter.first?</tt> would return +true+ if that chapter is
61
- # the first in the list of all chapters.
4
+
5
+ module ClassMethods
6
+ # Configuration options are:
7
+ #
8
+ # * +column+ - specifies the column name to use for keeping the position integer (default: +position+)
9
+ # * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach <tt>_id</tt>
10
+ # (if it hasn't already been added) and use that as the foreign key restriction. It's also possible
11
+ # to give it an entire string that is interpolated if you need a tighter scope than just a foreign key.
12
+ # Example: <tt>acts_as_list scope: 'todo_list_id = #{todo_list_id} AND completed = 0'</tt>
13
+ # * +top_of_list+ - defines the integer used for the top of the list. Defaults to 1. Use 0 to make the collection
14
+ # act more like an array in its indexing.
15
+ # * +add_new_at+ - specifies whether objects get added to the :top or :bottom of the list. (default: +bottom+)
16
+ # `nil` will result in new items not being added to the list on create.
17
+ # * +sequential_updates+ - specifies whether insert_at should update objects positions during shuffling
18
+ # one by one to respect position column unique not null constraint.
19
+ # Defaults to true if position column has unique index, otherwise false.
20
+ # If constraint is <tt>deferrable initially deferred<tt>, overriding it with false will speed up insert_at.
21
+ def acts_as_list(options = {})
22
+ configuration = { column: "position", scope: "1 = 1", top_of_list: 1, add_new_at: :bottom }
23
+ configuration.update(options) if options.is_a?(Hash)
24
+
25
+ caller_class = self
26
+
27
+ ActiveRecord::Acts::List::PositionColumnMethodDefiner.call(caller_class, configuration[:column])
28
+ ActiveRecord::Acts::List::ScopeMethodDefiner.call(caller_class, configuration[:scope])
29
+ ActiveRecord::Acts::List::TopOfListMethodDefiner.call(caller_class, configuration[:top_of_list])
30
+ ActiveRecord::Acts::List::AddNewAtMethodDefiner.call(caller_class, configuration[:add_new_at])
31
+
32
+ ActiveRecord::Acts::List::AuxMethodDefiner.call(caller_class)
33
+ ActiveRecord::Acts::List::CallbackDefiner.call(caller_class, configuration[:add_new_at])
34
+ ActiveRecord::Acts::List::SequentialUpdatesMethodDefiner.call(caller_class, configuration[:column], configuration[:sequential_updates])
35
+
36
+ include ActiveRecord::Acts::List::InstanceMethods
37
+ include ActiveRecord::Acts::List::NoUpdate
38
+ end
39
+
40
+ # This +acts_as+ extension provides the capabilities for sorting and reordering a number of objects in a list.
41
+ # The class that has this specified needs to have a +position+ column defined as an integer on
42
+ # the mapped database table.
43
+ #
44
+ # Todo list example:
45
+ #
46
+ # class TodoList < ActiveRecord::Base
47
+ # has_many :todo_items, order: "position"
48
+ # end
49
+ #
50
+ # class TodoItem < ActiveRecord::Base
51
+ # belongs_to :todo_list
52
+ # acts_as_list scope: :todo_list
53
+ # end
54
+ #
55
+ # todo_list.first.move_to_bottom
56
+ # todo_list.last.move_higher
57
+
58
+ # All the methods available to a record that has had <tt>acts_as_list</tt> specified. Each method works
59
+ # by assuming the object to be the item in the list, so <tt>chapter.move_lower</tt> would move that chapter
60
+ # lower in the list of all chapters. Likewise, <tt>chapter.first?</tt> would return +true+ if that chapter is
61
+ # the first in the list of all chapters.
62
+ end
63
+
62
64
  module InstanceMethods
63
65
  # Insert the item at the given position (defaults to the top position of 1).
64
66
  def insert_at(position = acts_as_list_top)
@@ -376,7 +378,7 @@ module ActiveRecord
376
378
  end
377
379
  end
378
380
  end
379
-
381
+
380
382
  def insert_at_position(position)
381
383
  return set_list_position(position) if new_record?
382
384
  with_lock do
@@ -408,7 +410,7 @@ module ActiveRecord
408
410
 
409
411
  def position_before_save
410
412
  if ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR >= 1 ||
411
- ActiveRecord::VERSION::MAJOR > 5
413
+ ActiveRecord::VERSION::MAJOR > 5
412
414
 
413
415
  send("#{position_column}_before_last_save")
414
416
  else
@@ -430,9 +432,9 @@ module ActiveRecord
430
432
  if internal_scope_changed?
431
433
  cached_changes = changes
432
434
 
433
- cached_changes.each { |attribute, values| self[attribute] = values[0] }
435
+ cached_changes.each { |attribute, values| send("#{attribute}=", values[0]) }
434
436
  send('decrement_positions_on_lower_items') if lower_item
435
- cached_changes.each { |attribute, values| self[attribute] = values[1] }
437
+ cached_changes.each { |attribute, values| send("#{attribute}=", values[1]) }
436
438
 
437
439
  send("add_to_list_#{add_new_at}") if add_new_at.present?
438
440
  end
@@ -460,6 +462,7 @@ module ActiveRecord
460
462
  @_quoted_position_column_with_table_name ||= "#{quoted_table_name}.#{quoted_position_column}"
461
463
  end
462
464
  end
465
+
463
466
  end
464
467
  end
465
468
  end
@@ -2,7 +2,10 @@ module ActiveRecord
2
2
  module Acts
3
3
  module List
4
4
  module NoUpdate
5
- extend ActiveSupport::Concern
5
+
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
6
9
 
7
10
  class ArrayTypeError < SyntaxError
8
11
  def initialize
@@ -96,9 +99,9 @@ module ActiveRecord
96
99
 
97
100
  private
98
101
 
99
- def extracted_klasses
100
- Thread.current[:act_as_list_no_update] ||= []
101
- end
102
+ def extracted_klasses
103
+ Thread.current[:act_as_list_no_update] ||= []
104
+ end
102
105
  end
103
106
 
104
107
  def act_as_list_no_update?
@@ -29,15 +29,13 @@ module ActiveRecord::Acts::List::PositionColumnMethodDefiner #:nodoc:
29
29
  end
30
30
 
31
31
  define_singleton_method :update_all_with_touch do |updates|
32
- record = new
33
- attrs = record.send(:timestamp_attributes_for_update_in_model)
34
- now = record.send(:current_time_from_proper_timezone)
32
+ update_all(updates << touch_record_sql)
33
+ end
35
34
 
36
- attrs.each do |attr|
37
- updates << ", #{connection.quote_column_name(attr)} = #{connection.quote(connection.quoted_date(now))}"
38
- end
35
+ private
39
36
 
40
- update_all(updates)
37
+ define_singleton_method :touch_record_sql do
38
+ new.touch_record_sql
41
39
  end
42
40
  end
43
41
  end
@@ -54,6 +52,23 @@ module ActiveRecord::Acts::List::PositionColumnMethodDefiner #:nodoc:
54
52
  write_attribute(position_column, position)
55
53
  @position_changed = true
56
54
  end
55
+
56
+ define_method :touch_record_sql do
57
+ cached_quoted_now = quoted_current_time_from_proper_timezone
58
+
59
+ timestamp_attributes_for_update_in_model.map do |attr|
60
+ ", #{connection.quote_column_name(attr)} = #{cached_quoted_now}"
61
+ end.join
62
+ end
63
+
64
+ private
65
+
66
+ delegate :connection, to: self
67
+
68
+ def quoted_current_time_from_proper_timezone
69
+ connection.quote(connection.quoted_date(
70
+ current_time_from_proper_timezone))
71
+ end
57
72
  end
58
73
  end
59
74
 
@@ -1,7 +1,7 @@
1
1
  module ActiveRecord
2
2
  module Acts
3
3
  module List
4
- VERSION = '0.9.5'
4
+ VERSION = '0.9.6'
5
5
  end
6
6
  end
7
7
  end
@@ -62,7 +62,7 @@ module Shared
62
62
 
63
63
  new = ArrayScopeListMixin.acts_as_list_no_update { ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass') }
64
64
  assert_equal_or_nil $default_position,new.pos
65
- assert_equal $default_position.is_a?(Fixnum), new.first?
65
+ assert_equal $default_position.is_a?(Integer), new.first?
66
66
  assert !new.last?
67
67
 
68
68
  new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
@@ -62,7 +62,7 @@ module Shared
62
62
 
63
63
  new = ListMixin.acts_as_list_no_update { ListMixin.create(parent_id: 20) }
64
64
  assert_equal_or_nil $default_position, new.pos
65
- assert_equal $default_position.is_a?(Fixnum), new.first?
65
+ assert_equal $default_position.is_a?(Integer), new.first?
66
66
  assert !new.last?
67
67
 
68
68
  new = ListMixin.create(parent_id: 20)
@@ -48,7 +48,7 @@ module Shared
48
48
 
49
49
  new = TopAdditionMixin.acts_as_list_no_update { TopAdditionMixin.create(parent_id: 20) }
50
50
  assert_equal_or_nil $default_position, new.pos
51
- assert_equal $default_position.is_a?(Fixnum), new.first?
51
+ assert_equal $default_position.is_a?(Integer), new.first?
52
52
  assert !new.last?
53
53
 
54
54
  new = TopAdditionMixin.create(parent_id: 20)
@@ -327,7 +327,7 @@ class DefaultScopedTest < ActsAsListTestCase
327
327
 
328
328
  new = DefaultScopedMixin.acts_as_list_no_update { DefaultScopedMixin.create }
329
329
  assert_equal_or_nil $default_position, new.pos
330
- assert_equal $default_position.is_a?(Fixnum), new.first?
330
+ assert_equal $default_position.is_a?(Integer), new.first?
331
331
  assert !new.last?
332
332
 
333
333
  new = DefaultScopedMixin.create
@@ -431,7 +431,7 @@ class DefaultScopedWhereTest < ActsAsListTestCase
431
431
 
432
432
  new = DefaultScopedWhereMixin.acts_as_list_no_update { DefaultScopedWhereMixin.create }
433
433
  assert_equal_or_nil $default_position, new.pos
434
- assert_equal $default_position.is_a?(Fixnum), new.first?
434
+ assert_equal $default_position.is_a?(Integer), new.first?
435
435
  assert !new.last?
436
436
 
437
437
  new = DefaultScopedWhereMixin.create
@@ -641,6 +641,12 @@ if rails_4
641
641
  assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['active']).map(&:pos)
642
642
  assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['archived']).map(&:pos)
643
643
  end
644
+
645
+ def test_update_state
646
+ active_item = EnumArrayScopeListMixin.find_by(:parent_id => 2, :state => EnumArrayScopeListMixin.states['active'])
647
+ active_item.update(state: EnumArrayScopeListMixin.states['archived'])
648
+ assert_equal [1, 2], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['archived']).map(&:pos).sort
649
+ end
644
650
  end
645
651
  end
646
652
 
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.9.5
4
+ version: 0.9.6
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: 2017-04-04 00:00:00.000000000 Z
13
+ date: 2017-07-05 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -66,6 +66,7 @@ files:
66
66
  - gemfiles/rails_5_1.gemfile
67
67
  - init.rb
68
68
  - lib/acts_as_list.rb
69
+ - lib/acts_as_list/active_record/acts/active_record.rb
69
70
  - lib/acts_as_list/active_record/acts/add_new_at_method_definer.rb
70
71
  - lib/acts_as_list/active_record/acts/aux_method_definer.rb
71
72
  - lib/acts_as_list/active_record/acts/callback_definer.rb