acts_as_list 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
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