acts_as_list 0.9.2 → 0.9.3

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: 5389d6284e204b5d24d21e0059706dfca2f6ffb4
4
- data.tar.gz: 8c70ec4d0148e815bd1261a2ab29db12dc7c1446
3
+ metadata.gz: 4602fbf2208d5b39ba3a0fe78b4ab3ad0947e69a
4
+ data.tar.gz: f3ef72c6695c6441366c657f41a3d8b273e7c588
5
5
  SHA512:
6
- metadata.gz: 9612ad3b4bf5ba60f8ff652acac46905c384349b2c63521b36a90ef11e24e1342db72bcded83fc6b1eb9944b37c5297a799460068f2c445a3adaf256930b70dd
7
- data.tar.gz: a0efb9b5b14c53871437c4562a2ff073d7ad7088c896aaccb2a43c2ab7cacf86d4447c871f9af7dcdab2fa21f6f2e994fa61871aa262a4d1544e878e7e3eace6
6
+ metadata.gz: 499b30c7a96fb04f2ab8c66414c7165686652b4969692a1e82a3af482b6f54e49d2270ed902466721874d0fcbe144cbc541fad09b55f22c385a0f181ffca8b3d
7
+ data.tar.gz: 38ae417b51053320bf227a3be9b44c8de46f754990bd4d74e427c47da6502e282e20c02ce4a47dc0466ee488c73fec14f8b44af660645379a412c9632ed2e29b
@@ -15,6 +15,7 @@ rvm:
15
15
  - 2.1.9
16
16
  - 2.2.6
17
17
  - 2.3.3
18
+ - 2.4.0
18
19
  - jruby-19mode
19
20
  env:
20
21
  - DB=sqlite
@@ -25,13 +26,26 @@ gemfile:
25
26
  - gemfiles/rails_4_1.gemfile
26
27
  - gemfiles/rails_4_2.gemfile
27
28
  - gemfiles/rails_5_0.gemfile
29
+ - gemfiles/rails_5_1.gemfile
28
30
  matrix:
29
31
  exclude:
30
32
  - rvm: 1.9.3
31
33
  gemfile: gemfiles/rails_5_0.gemfile
34
+ - rvm: 1.9.3
35
+ gemfile: gemfiles/rails_5_1.gemfile
32
36
  - rvm: 2.0.0
33
37
  gemfile: gemfiles/rails_5_0.gemfile
38
+ - rvm: 2.0.0
39
+ gemfile: gemfiles/rails_5_1.gemfile
34
40
  - rvm: 2.1.9
35
41
  gemfile: gemfiles/rails_5_0.gemfile
42
+ - rvm: 2.1.9
43
+ gemfile: gemfiles/rails_5_1.gemfile
44
+ - rvm: 2.4.0
45
+ gemfile: gemfiles/rails_3_2.gemfile
46
+ - rvm: 2.4.0
47
+ gemfile: gemfiles/rails_4_1.gemfile
36
48
  - rvm: jruby-19mode
37
49
  gemfile: gemfiles/rails_5_0.gemfile
50
+ - rvm: jruby-19mode
51
+ gemfile: gemfiles/rails_5_1.gemfile
data/Appraisals CHANGED
@@ -19,3 +19,7 @@ end
19
19
  appraise "rails-5-0" do
20
20
  gem "activerecord", "~> 5.0.0"
21
21
  end
22
+
23
+ appraise "rails-5-1" do
24
+ gem "activerecord", "~> 5.1.0.beta1"
25
+ end
@@ -1,5 +1,12 @@
1
1
  # Change Log
2
2
 
3
+ ## [v0.9.2](https://github.com/swanandp/acts_as_list/tree/v0.9.2) (2017-02-07)
4
+ [Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.1...v0.9.2)
5
+
6
+ **Closed issues:**
7
+
8
+ - Getting invalid input syntax for uuid [\#253](https://github.com/swanandp/acts_as_list/issues/253)
9
+
3
10
  ## [v0.9.1](https://github.com/swanandp/acts_as_list/tree/v0.9.1) (2017-01-26)
4
11
  [Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.0...v0.9.1)
5
12
 
data/Gemfile CHANGED
@@ -12,6 +12,7 @@ group :test do
12
12
  gem "minitest", "~> 5.0"
13
13
  gem "test_after_commit", "~> 0.4.2"
14
14
  gem "timecop"
15
+ gem "mocha"
15
16
  end
16
17
 
17
18
  group :sqlite do
data/README.md CHANGED
@@ -27,27 +27,27 @@ At first, you need to add a `position` column to desired table:
27
27
 
28
28
  rails g migration AddPositionToTodoItem position:integer
29
29
  rake db:migrate
30
-
31
- After that you can use `acts_as_list` method in the model:
30
+
31
+ After that you can use `acts_as_list` method in the model:
32
32
 
33
33
  ```ruby
34
34
  class TodoList < ActiveRecord::Base
35
35
  has_many :todo_items, -> { order(position: :asc) }
36
36
  end
37
-
37
+
38
38
  class TodoItem < ActiveRecord::Base
39
39
  belongs_to :todo_list
40
40
  acts_as_list scope: :todo_list
41
41
  end
42
42
 
43
- todo_list = TodoList.find(...)
43
+ todo_list = TodoList.find(...)
44
44
  todo_list.todo_items.first.move_to_bottom
45
45
  todo_list.todo_items.last.move_higher
46
46
  ```
47
47
 
48
48
  ## Instance Methods Added To ActiveRecord Models
49
49
 
50
- You'll have a number of methods added to each instance of the ActiveRecord model that to which `acts_as_list` is added.
50
+ You'll have a number of methods added to each instance of the ActiveRecord model that to which `acts_as_list` is added.
51
51
 
52
52
  In `acts_as_list`, "higher" means further up the list (a lower `position`), and "lower" means further down the list (a higher `position`). That can be confusing, so it might make sense to add tests that validate that you're using the right method given your context.
53
53
 
@@ -132,7 +132,34 @@ TodoItem.acts_as_list_no_update do
132
132
  end
133
133
  ```
134
134
  In an `acts_as_list_no_update` block, all callbacks are disabled, and positions are not updated. New records will be created with
135
- the default value from the database. It is your responsibility to correctly manage `positions` values.
135
+ the default value from the database. It is your responsibility to correctly manage `positions` values.
136
+
137
+ You can also pass an array of classes as an argument to disable database updates on just those classes. It can be any ActiveRecord class that has acts_as_list enabled.
138
+ ```ruby
139
+ class TodoList < ActiveRecord::Base
140
+ has_many :todo_items, -> { order(position: :asc) }
141
+ acts_as_list
142
+ end
143
+
144
+ class TodoItem < ActiveRecord::Base
145
+ belongs_to :todo_list
146
+ has_many :todo_attachments, -> { order(position: :asc) }
147
+
148
+ acts_as_list scope: :todo_list
149
+ end
150
+
151
+ class TodoAttachment < ActiveRecord::Base
152
+ belongs_to :todo_list
153
+ acts_as_list scope: :todo_item
154
+ end
155
+
156
+ TodoItem.acts_as_list_no_update([TodoAttachment]) do
157
+ TodoItem.find(10).update(position: 2)
158
+ TodoAttachment.find(10).update(position: 1)
159
+ TodoAttachment.find(11).update(position: 2)
160
+ TodoList.find(2).update(position: 3) # For this instance the callbacks will be called because we haven't passed the class as an argument
161
+ end
162
+ ```
136
163
 
137
164
  ## Versions
138
165
  Version `0.9.0` adds `acts_as_list_no_update` (https://github.com/swanandp/acts_as_list/pull/244) and compatibility with not-null and uniqueness constraints on the database (https://github.com/swanandp/acts_as_list/pull/246). These additions shouldn't break compatibility with existing implementations.
@@ -152,7 +179,7 @@ All versions `0.1.5` onwards require Rails 3.0.x and higher.
152
179
  1. Sort based feature
153
180
 
154
181
  ## Contributing to `acts_as_list`
155
-
182
+
156
183
  - Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
157
184
  - Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
158
185
  - Fork the project
@@ -12,6 +12,7 @@ group :test do
12
12
  gem "minitest", "~> 5.0"
13
13
  gem "test_after_commit", "~> 0.4.2"
14
14
  gem "timecop"
15
+ gem "mocha"
15
16
  gem "after_commit_exception_notification"
16
17
  end
17
18
 
@@ -12,6 +12,7 @@ group :test do
12
12
  gem "minitest", "~> 5.0"
13
13
  gem "test_after_commit", "~> 0.4.2"
14
14
  gem "timecop"
15
+ gem "mocha"
15
16
  gem "after_commit_exception_notification"
16
17
  end
17
18
 
@@ -12,6 +12,7 @@ group :test do
12
12
  gem "minitest", "~> 5.0"
13
13
  gem "test_after_commit", "~> 0.4.2"
14
14
  gem "timecop"
15
+ gem "mocha"
15
16
  end
16
17
 
17
18
  group :sqlite do
@@ -12,6 +12,7 @@ group :test do
12
12
  gem "minitest", "~> 5.0"
13
13
  gem "test_after_commit", "~> 0.4.2"
14
14
  gem "timecop"
15
+ gem "mocha"
15
16
  end
16
17
 
17
18
  group :sqlite do
@@ -0,0 +1,33 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rack", "~> 1", :platforms => [:ruby_19, :ruby_20, :ruby_21, :jruby]
6
+ gem "rake"
7
+ gem "appraisal"
8
+ gem "github_changelog_generator", "1.9.0"
9
+ gem "activerecord", "~> 5.1.0.beta1"
10
+
11
+ group :test do
12
+ gem "minitest", "~> 5.0"
13
+ gem "test_after_commit", "~> 0.4.2"
14
+ gem "timecop"
15
+ gem "mocha"
16
+ end
17
+
18
+ group :sqlite do
19
+ gem "sqlite3", :platforms => [:ruby]
20
+ gem "activerecord-jdbcsqlite3-adapter", :platforms => [:jruby]
21
+ end
22
+
23
+ group :postgresql do
24
+ gem "pg", "~> 0.18.0", :platforms => [:ruby]
25
+ gem "activerecord-jdbcpostgresql-adapter", :platforms => [:jruby]
26
+ end
27
+
28
+ group :mysql do
29
+ gem "mysql2", "~> 0.3.10", :platforms => [:ruby]
30
+ gem "activerecord-jdbcmysql-adapter", :platforms => [:jruby]
31
+ end
32
+
33
+ gemspec :path => "../"
@@ -1,5 +1,5 @@
1
1
  require 'acts_as_list/active_record/acts/list'
2
- require "acts_as_list/active_record/acts/column_method_definer"
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"
@@ -3,8 +3,8 @@ module ActiveRecord::Acts::List::CallbackDefiner #:nodoc:
3
3
  caller_class.class_eval do
4
4
  before_validation :check_top_position, unless: :act_as_list_no_update?
5
5
 
6
- before_destroy :lock!
7
- after_destroy :decrement_positions_on_lower_items, unless: :act_as_list_no_update?
6
+ before_destroy :lock!, unless: "destroyed_via_scope? || act_as_list_no_update?"
7
+ after_destroy :decrement_positions_on_lower_items, unless: "destroyed_via_scope? || act_as_list_no_update?"
8
8
 
9
9
  before_update :check_scope, unless: :act_as_list_no_update?
10
10
  after_update :update_positions, unless: :act_as_list_no_update?
@@ -20,7 +20,7 @@ class << ActiveRecord::Base
20
20
 
21
21
  caller_class = self
22
22
 
23
- ActiveRecord::Acts::List::ColumnMethodDefiner.call(caller_class, configuration[:column])
23
+ ActiveRecord::Acts::List::PositionColumnMethodDefiner.call(caller_class, configuration[:column])
24
24
  ActiveRecord::Acts::List::ScopeMethodDefiner.call(caller_class, configuration[:scope])
25
25
  ActiveRecord::Acts::List::TopOfListMethodDefiner.call(caller_class, configuration[:top_of_list])
26
26
  ActiveRecord::Acts::List::AddNewAtMethodDefiner.call(caller_class, configuration[:add_new_at])
@@ -393,7 +393,7 @@ module ActiveRecord
393
393
  end
394
394
 
395
395
  def update_positions
396
- old_position = send("#{position_column}_was") || bottom_position_in_list + 1
396
+ old_position = position_before_save || bottom_position_in_list + 1
397
397
  new_position = send(position_column).to_i
398
398
 
399
399
  return unless acts_as_list_list.where(
@@ -402,6 +402,14 @@ module ActiveRecord
402
402
  shuffle_positions_on_intermediate_items old_position, new_position, id
403
403
  end
404
404
 
405
+ def position_before_save
406
+ if ActiveRecord::VERSION::MAJOR >= 5 && ActiveRecord::VERSION::MINOR >= 1
407
+ send("#{position_column}_before_last_save")
408
+ else
409
+ send("#{position_column}_was")
410
+ end
411
+ end
412
+
405
413
  def internal_scope_changed?
406
414
  return @scope_changed if defined?(@scope_changed)
407
415
 
@@ -4,39 +4,99 @@ module ActiveRecord
4
4
  module NoUpdate
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ class ArrayTypeError < SyntaxError
8
+ def initialize
9
+ super("The first argument must be an array")
10
+ end
11
+ end
12
+
13
+ class DisparityClassesError < NotImplementedError
14
+ def initialize
15
+ super("The first argument should contain ActiveRecord or ApplicationRecord classes")
16
+ end
17
+ end
18
+
7
19
  module ClassMethods
8
20
  # Lets you selectively disable all act_as_list database updates
9
21
  # for the duration of a block.
10
22
  #
11
23
  # ==== Examples
12
- # ActiveRecord::Acts::List.acts_as_list_no_update do
13
- # TodoList....
14
- # end
15
24
  #
16
- # TodoList.acts_as_list_no_update do
17
- # TodoList....
18
- # end
25
+ # class TodoList < ActiveRecord::Base
26
+ # has_many :todo_items, -> { order(position: :asc) }
27
+ # end
28
+ #
29
+ # class TodoItem < ActiveRecord::Base
30
+ # belongs_to :todo_list
31
+ #
32
+ # acts_as_list scope: :todo_list
33
+ # end
34
+ #
35
+ # TodoItem.acts_as_list_no_update do
36
+ # TodoList.first.update(position: 2)
37
+ # end
38
+ #
39
+ # You can also pass an array of classes as an argument to disable database updates on just those classes.
40
+ # It can be any ActiveRecord class that has acts_as_list enabled.
41
+ #
42
+ # ==== Examples
43
+ #
44
+ # class TodoList < ActiveRecord::Base
45
+ # has_many :todo_items, -> { order(position: :asc) }
46
+ # acts_as_list
47
+ # end
48
+ #
49
+ # class TodoItem < ActiveRecord::Base
50
+ # belongs_to :todo_list
51
+ # has_many :todo_attachments, -> { order(position: :asc) }
52
+ #
53
+ # acts_as_list scope: :todo_list
54
+ # end
19
55
  #
20
- def acts_as_list_no_update(&block)
21
- NoUpdate.apply_to(self, &block)
56
+ # class TodoAttachment < ActiveRecord::Base
57
+ # belongs_to :todo_list
58
+ # acts_as_list scope: :todo_item
59
+ # end
60
+ #
61
+ # TodoItem.acts_as_list_no_update([TodoAttachment]) do
62
+ # TodoItem.find(10).update(position: 2)
63
+ # TodoAttachment.find(10).update(position: 1)
64
+ # TodoAttachment.find(11).update(position: 2)
65
+ # TodoList.find(2).update(position: 3) # For this instance the callbacks will be called because we haven't passed the class as an argument
66
+ # end
67
+
68
+ def acts_as_list_no_update(extra_classes = [], &block)
69
+ return raise ArrayTypeError unless extra_classes.is_a?(Array)
70
+
71
+ extra_classes << self
72
+
73
+ return raise DisparityClassesError unless active_record_objects?(extra_classes)
74
+
75
+ NoUpdate.apply_to(extra_classes, &block)
76
+ end
77
+
78
+ private
79
+
80
+ def active_record_objects?(extra_classes)
81
+ extra_classes.all? { |klass| klass.ancestors.include? ActiveRecord::Base }
22
82
  end
23
83
  end
24
84
 
25
85
  class << self
26
- def apply_to(klass)
27
- klasses.push(klass)
86
+ def apply_to(klasses)
87
+ extracted_klasses.push(*klasses)
28
88
  yield
29
89
  ensure
30
- klasses.pop
90
+ extracted_klasses.clear
31
91
  end
32
92
 
33
93
  def applied_to?(klass)
34
- klasses.any? { |k| k >= klass }
94
+ extracted_klasses.any? { |k| k == klass }
35
95
  end
36
96
 
37
97
  private
38
98
 
39
- def klasses
99
+ def extracted_klasses
40
100
  Thread.current[:act_as_list_no_update] ||= []
41
101
  end
42
102
  end
@@ -1,25 +1,19 @@
1
- module ActiveRecord::Acts::List::ColumnMethodDefiner #:nodoc:
2
- def self.call(caller_class, column)
3
- caller_class.class_eval do
4
- attr_reader :position_changed
5
-
6
- define_method :position_column do
7
- column
8
- end
1
+ module ActiveRecord::Acts::List::PositionColumnMethodDefiner #:nodoc:
2
+ def self.call(caller_class, position_column)
3
+ define_class_methods(caller_class, position_column)
4
+ define_instance_methods(caller_class, position_column)
9
5
 
10
- define_method :"#{column}=" do |position|
11
- write_attribute(column, position)
12
- @position_changed = true
13
- end
6
+ if mass_assignment_protection_was_used_by_user?(caller_class)
7
+ protect_attributes_from_mass_assignment(caller_class, position_column)
8
+ end
9
+ end
14
10
 
15
- # only add to attr_accessible
16
- # if the class has some mass_assignment_protection
17
- if defined?(accessible_attributes) and !accessible_attributes.blank?
18
- attr_accessible :"#{column}"
19
- end
11
+ private
20
12
 
13
+ def self.define_class_methods(caller_class, position_column)
14
+ caller_class.class_eval do
21
15
  define_singleton_method :quoted_position_column do
22
- @_quoted_position_column ||= connection.quote_column_name(column)
16
+ @_quoted_position_column ||= connection.quote_column_name(position_column)
23
17
  end
24
18
 
25
19
  define_singleton_method :quoted_position_column_with_table_name do
@@ -47,4 +41,31 @@ module ActiveRecord::Acts::List::ColumnMethodDefiner #:nodoc:
47
41
  end
48
42
  end
49
43
  end
44
+
45
+ def self.define_instance_methods(caller_class, position_column)
46
+ caller_class.class_eval do
47
+ attr_reader :position_changed
48
+
49
+ define_method :position_column do
50
+ position_column
51
+ end
52
+
53
+ define_method :"#{position_column}=" do |position|
54
+ write_attribute(position_column, position)
55
+ @position_changed = true
56
+ end
57
+ end
58
+ end
59
+
60
+ def self.mass_assignment_protection_was_used_by_user?(caller_class)
61
+ caller_class.class_eval do
62
+ respond_to?(:accessible_attributes) and accessible_attributes.present?
63
+ end
64
+ end
65
+
66
+ def self.protect_attributes_from_mass_assignment(caller_class, position_column)
67
+ caller_class.class_eval do
68
+ attr_accessible position_column.to_sym
69
+ end
70
+ end
50
71
  end
@@ -17,6 +17,11 @@ module ActiveRecord::Acts::List::ScopeMethodDefiner #:nodoc:
17
17
  define_method :scope_changed? do
18
18
  changed.include?(scope_name.to_s)
19
19
  end
20
+
21
+ define_method :destroyed_via_scope? do
22
+ return false if ActiveRecord::VERSION::MAJOR < 4
23
+ scope == (destroyed_by_association && destroyed_by_association.foreign_key.to_sym)
24
+ end
20
25
  elsif scope.is_a?(Array)
21
26
  define_method :scope_condition do
22
27
  scope.inject({}) do |hash, column|
@@ -27,6 +32,11 @@ module ActiveRecord::Acts::List::ScopeMethodDefiner #:nodoc:
27
32
  define_method :scope_changed? do
28
33
  (scope_condition.keys & changed.map(&:to_sym)).any?
29
34
  end
35
+
36
+ define_method :destroyed_via_scope? do
37
+ return false if ActiveRecord::VERSION::MAJOR < 4
38
+ scope_condition.keys.include? (destroyed_by_association && destroyed_by_association.foreign_key.to_sym)
39
+ end
30
40
  else
31
41
  define_method :scope_condition do
32
42
  eval "%{#{scope}}"
@@ -35,6 +45,10 @@ module ActiveRecord::Acts::List::ScopeMethodDefiner #:nodoc:
35
45
  define_method :scope_changed? do
36
46
  false
37
47
  end
48
+
49
+ define_method :destroyed_via_scope? do
50
+ false
51
+ end
38
52
  end
39
53
 
40
54
  self.scope :in_list, lambda { where("#{quoted_position_column_with_table_name} IS NOT NULL") }
@@ -1,7 +1,7 @@
1
1
  module ActiveRecord
2
2
  module Acts
3
3
  module List
4
- VERSION = '0.9.2'
4
+ VERSION = '0.9.3'
5
5
  end
6
6
  end
7
7
  end
@@ -11,6 +11,7 @@ rescue Bundler::BundlerError => e
11
11
  end
12
12
  require "active_record"
13
13
  require "minitest/autorun"
14
+ require "mocha/mini_test"
14
15
  require "#{File.dirname(__FILE__)}/../init"
15
16
 
16
17
  if defined?(ActiveRecord::VERSION) &&
@@ -20,6 +21,31 @@ if defined?(ActiveRecord::VERSION) &&
20
21
  ActiveRecord::Base.raise_in_transactional_callbacks = true
21
22
  end
22
23
 
24
+ db_config = YAML.load_file(File.expand_path("../database.yml", __FILE__)).fetch(ENV["DB"] || "sqlite")
25
+ ActiveRecord::Base.establish_connection(db_config)
26
+ ActiveRecord::Schema.verbose = false
27
+
28
+ # Returns true if ActiveRecord is rails 3, 4 version
29
+ def rails_3
30
+ defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::MAJOR >= 3
31
+ end
32
+
33
+ def rails_4
34
+ defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::MAJOR >= 4
35
+ end
36
+
37
+ def teardown_db
38
+ if ActiveRecord::VERSION::MAJOR >= 5
39
+ tables = ActiveRecord::Base.connection.data_sources
40
+ else
41
+ tables = ActiveRecord::Base.connection.tables
42
+ end
43
+
44
+ tables.each do |table|
45
+ ActiveRecord::Base.connection.drop_table(table)
46
+ end
47
+ end
48
+
23
49
  require "shared"
24
50
 
25
51
  # ActiveRecord::Base.logger = Logger.new(STDOUT)
@@ -30,4 +56,4 @@ def assert_equal_or_nil(a, b)
30
56
  else
31
57
  assert_equal a, b
32
58
  end
33
- end
59
+ end
@@ -1,9 +1,5 @@
1
1
  require 'helper'
2
2
 
3
- db_config = YAML.load_file(File.expand_path("../database.yml", __FILE__)).fetch(ENV["DB"] || "sqlite")
4
- ActiveRecord::Base.establish_connection(db_config)
5
- ActiveRecord::Schema.verbose = false
6
-
7
3
  class Section < ActiveRecord::Base
8
4
  has_many :items
9
5
  acts_as_list
@@ -37,14 +33,7 @@ class JoinedTestCase < Minitest::Test
37
33
  end
38
34
 
39
35
  def teardown
40
- if ActiveRecord::VERSION::MAJOR >= 5
41
- tables = ActiveRecord::Base.connection.data_sources
42
- else
43
- tables = ActiveRecord::Base.connection.tables
44
- end
45
- tables.each do |table|
46
- ActiveRecord::Base.connection.drop_table(table)
47
- end
36
+ teardown_db
48
37
  super
49
38
  end
50
39
  end
@@ -1,13 +1,9 @@
1
1
  # NOTE: following now done in helper.rb (better Readability)
2
2
  require 'helper'
3
3
 
4
- db_config = YAML.load_file(File.expand_path("../database.yml", __FILE__)).fetch(ENV["DB"] || "sqlite")
5
- ActiveRecord::Base.establish_connection(db_config)
6
- ActiveRecord::Schema.verbose = false
7
-
8
4
  def setup_db(position_options = {})
9
5
  $default_position = position_options[:default]
10
-
6
+
11
7
  # sqlite cannot drop/rename/alter columns and add constraints after table creation
12
8
  sqlite = ENV.fetch("DB", "sqlite") == "sqlite"
13
9
 
@@ -25,7 +21,7 @@ def setup_db(position_options = {})
25
21
  if position_options[:unique] && !(sqlite && position_options[:positive])
26
22
  ActiveRecord::Base.connection.add_index :mixins, :pos, unique: true
27
23
  end
28
-
24
+
29
25
  if position_options[:positive]
30
26
  if sqlite
31
27
  # SQLite cannot add constraint after table creation, also cannot add unique inside ADD COLUMN
@@ -57,27 +53,6 @@ def setup_db_with_default
57
53
  setup_db default: 0
58
54
  end
59
55
 
60
- # Returns true if ActiveRecord is rails3,4 version
61
- def rails_3
62
- defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::MAJOR >= 3
63
- end
64
-
65
- def rails_4
66
- defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::MAJOR >= 4
67
- end
68
-
69
- def teardown_db
70
- if ActiveRecord::VERSION::MAJOR >= 5
71
- tables = ActiveRecord::Base.connection.data_sources
72
- else
73
- tables = ActiveRecord::Base.connection.tables
74
- end
75
-
76
- tables.each do |table|
77
- ActiveRecord::Base.connection.drop_table(table)
78
- end
79
- end
80
-
81
56
  class Mixin < ActiveRecord::Base
82
57
  self.table_name = 'mixins'
83
58
  end
@@ -0,0 +1,104 @@
1
+ require 'helper'
2
+
3
+ class TodoList < ActiveRecord::Base
4
+ has_many :todo_items
5
+ acts_as_list
6
+ end
7
+
8
+ class TodoItem < ActiveRecord::Base
9
+ belongs_to :todo_list
10
+ has_many :todo_item_attachments
11
+ acts_as_list scope: :todo_list
12
+ end
13
+
14
+ class TodoItemAttachment < ActiveRecord::Base
15
+ belongs_to :todo_item
16
+ acts_as_list scope: :todo_item
17
+ end
18
+
19
+ class NoUpdateForCollectionClassesTestCase < Minitest::Test
20
+ def setup
21
+ ActiveRecord::Base.connection.create_table :todo_lists do |t|
22
+ t.column :position, :integer
23
+ end
24
+
25
+ ActiveRecord::Base.connection.create_table :todo_items do |t|
26
+ t.column :position, :integer
27
+ t.column :todo_list_id, :integer
28
+ end
29
+
30
+ ActiveRecord::Base.connection.create_table :todo_item_attachments do |t|
31
+ t.column :position, :integer
32
+ t.column :todo_item_id, :integer
33
+ end
34
+
35
+ ActiveRecord::Base.connection.schema_cache.clear!
36
+ [TodoList, TodoItem, TodoItemAttachment].each(&:reset_column_information)
37
+ super
38
+ end
39
+
40
+ def teardown
41
+ teardown_db
42
+ super
43
+ end
44
+ end
45
+
46
+ class NoUpdateForCollectionClassesTest < NoUpdateForCollectionClassesTestCase
47
+ def setup
48
+ super
49
+ @list_1, @list_2 = (1..2).map { |counter| TodoList.create!(position: counter) }
50
+
51
+ @item_1, @item_2 = (1..2).map { |counter| TodoItem.create!(position: counter, todo_list_id: @list_1.id) }
52
+ @attachment_1, @attachment_2 = (1..2).map { |counter| TodoItemAttachment.create!(position: counter, todo_item_id: @item_1.id) }
53
+ end
54
+
55
+ def test_update
56
+ @item_1.update_attributes(position: 2)
57
+ assert_equal 2, @item_1.reload.position
58
+ assert_equal 1, @item_2.reload.position
59
+ end
60
+
61
+ def test_no_update_for_single_class_instances
62
+ TodoItem.acts_as_list_no_update { @item_1.update_attributes(position: 2) }
63
+
64
+ assert_equal 2, @item_1.reload.position
65
+ assert_equal 2, @item_2.reload.position
66
+ end
67
+
68
+ def test_no_update_for_different_class_instances
69
+ TodoItem.acts_as_list_no_update([TodoItemAttachment]) { update_records! }
70
+
71
+ assert_equal 2, @item_1.reload.position
72
+ assert_equal 2, @item_2.reload.position
73
+
74
+ assert_equal 2, @attachment_1.reload.position
75
+ assert_equal 2, @attachment_2.reload.position
76
+
77
+ assert_equal 2, @list_1.reload.position
78
+ assert_equal 1, @list_2.reload.position
79
+ end
80
+
81
+ def test_raising_array_type_error
82
+ exception = assert_raises ActiveRecord::Acts::List::NoUpdate::ArrayTypeError do
83
+ TodoList.acts_as_list_no_update(nil)
84
+ end
85
+
86
+ assert_equal("The first argument must be an array", exception.message )
87
+ end
88
+
89
+ def test_non_disparity_classes_error
90
+ exception = assert_raises ActiveRecord::Acts::List::NoUpdate::DisparityClassesError do
91
+ TodoList.acts_as_list_no_update([Class])
92
+ end
93
+
94
+ assert_equal("The first argument should contain ActiveRecord or ApplicationRecord classes", exception.message )
95
+ end
96
+
97
+ private
98
+
99
+ def update_records!
100
+ @item_1.update_attributes(position: 2)
101
+ @attachment_1.update_attributes(position: 2)
102
+ @list_1.update_attributes(position: 2)
103
+ end
104
+ end
@@ -0,0 +1,72 @@
1
+ require 'helper'
2
+
3
+ class DestructionTodoList < ActiveRecord::Base
4
+ has_many :destruction_todo_items, dependent: :destroy
5
+ has_many :destruction_tada_items, dependent: :destroy
6
+ end
7
+
8
+ class DestructionTodoItem < ActiveRecord::Base
9
+ belongs_to :destruction_todo_list
10
+ acts_as_list scope: :destruction_todo_list
11
+ end
12
+
13
+ class DestructionTadaItem < ActiveRecord::Base
14
+ belongs_to :destruction_todo_list
15
+ acts_as_list scope: [:destruction_todo_list_id, :enabled]
16
+ end
17
+
18
+ class NoUpdateForScopeDestructionTestCase < Minitest::Test
19
+ def setup
20
+ ActiveRecord::Base.connection.create_table :destruction_todo_lists do |t|
21
+ end
22
+
23
+ ActiveRecord::Base.connection.create_table :destruction_todo_items do |t|
24
+ t.column :position, :integer
25
+ t.column :destruction_todo_list_id, :integer
26
+ end
27
+
28
+ ActiveRecord::Base.connection.create_table :destruction_tada_items do |t|
29
+ t.column :position, :integer
30
+ t.column :destruction_todo_list_id, :integer
31
+ t.column :enabled, :boolean
32
+ end
33
+
34
+ ActiveRecord::Base.connection.schema_cache.clear!
35
+ [DestructionTodoList, DestructionTodoItem, DestructionTadaItem].each(&:reset_column_information)
36
+ super
37
+ end
38
+
39
+ def teardown
40
+ teardown_db
41
+ super
42
+ end
43
+
44
+ class NoUpdateForScopeDestructionTest < NoUpdateForScopeDestructionTestCase
45
+ def setup
46
+ super
47
+ @list = DestructionTodoList.create!
48
+
49
+ @todo_item_1 = DestructionTodoItem.create! position: 1, destruction_todo_list_id: @list.id
50
+ @tada_item_1 = DestructionTadaItem.create! position: 1, destruction_todo_list_id: @list.id, enabled: true
51
+ end
52
+
53
+ def test_no_update_children_when_parent_destroyed
54
+ if ActiveRecord::VERSION::MAJOR < 4
55
+ DestructionTodoItem.any_instance.expects(:decrement_positions_on_lower_items).once
56
+ DestructionTadaItem.any_instance.expects(:decrement_positions_on_lower_items).once
57
+ else
58
+ DestructionTodoItem.any_instance.expects(:decrement_positions_on_lower_items).never
59
+ DestructionTadaItem.any_instance.expects(:decrement_positions_on_lower_items).never
60
+ end
61
+ assert @list.destroy
62
+ end
63
+
64
+ def test_update_children_when_sibling_destroyed
65
+ @todo_item_1.expects(:decrement_positions_on_lower_items).once
66
+ @tada_item_1.expects(:decrement_positions_on_lower_items).once
67
+ assert @todo_item_1.destroy
68
+ assert @tada_item_1.destroy
69
+ end
70
+
71
+ end
72
+ end
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.2
4
+ version: 0.9.3
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-02-07 00:00:00.000000000 Z
13
+ date: 2017-03-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -63,14 +63,15 @@ files:
63
63
  - gemfiles/rails_4_1.gemfile
64
64
  - gemfiles/rails_4_2.gemfile
65
65
  - gemfiles/rails_5_0.gemfile
66
+ - gemfiles/rails_5_1.gemfile
66
67
  - init.rb
67
68
  - lib/acts_as_list.rb
68
69
  - lib/acts_as_list/active_record/acts/add_new_at_method_definer.rb
69
70
  - lib/acts_as_list/active_record/acts/aux_method_definer.rb
70
71
  - lib/acts_as_list/active_record/acts/callback_definer.rb
71
- - lib/acts_as_list/active_record/acts/column_method_definer.rb
72
72
  - lib/acts_as_list/active_record/acts/list.rb
73
73
  - lib/acts_as_list/active_record/acts/no_update.rb
74
+ - lib/acts_as_list/active_record/acts/position_column_method_definer.rb
74
75
  - lib/acts_as_list/active_record/acts/scope_method_definer.rb
75
76
  - lib/acts_as_list/active_record/acts/sequential_updates_method_definer.rb
76
77
  - lib/acts_as_list/active_record/acts/top_of_list_method_definer.rb
@@ -87,6 +88,8 @@ files:
87
88
  - test/shared_zero_based.rb
88
89
  - test/test_joined_list.rb
89
90
  - test/test_list.rb
91
+ - test/test_no_update_for_extra_classes.rb
92
+ - test/test_no_update_for_scope_destruction.rb
90
93
  homepage: http://github.com/swanandp/acts_as_list
91
94
  licenses:
92
95
  - MIT
@@ -125,3 +128,5 @@ test_files:
125
128
  - test/shared_zero_based.rb
126
129
  - test/test_joined_list.rb
127
130
  - test/test_list.rb
131
+ - test/test_no_update_for_extra_classes.rb
132
+ - test/test_no_update_for_scope_destruction.rb