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 +4 -4
- data/.travis.yml +14 -0
- data/Appraisals +4 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +1 -0
- data/README.md +34 -7
- data/gemfiles/rails_3_2.gemfile +1 -0
- data/gemfiles/rails_4_1.gemfile +1 -0
- data/gemfiles/rails_4_2.gemfile +1 -0
- data/gemfiles/rails_5_0.gemfile +1 -0
- data/gemfiles/rails_5_1.gemfile +33 -0
- data/lib/acts_as_list.rb +1 -1
- data/lib/acts_as_list/active_record/acts/callback_definer.rb +2 -2
- data/lib/acts_as_list/active_record/acts/list.rb +10 -2
- data/lib/acts_as_list/active_record/acts/no_update.rb +73 -13
- data/lib/acts_as_list/active_record/acts/{column_method_definer.rb → position_column_method_definer.rb} +39 -18
- data/lib/acts_as_list/active_record/acts/scope_method_definer.rb +14 -0
- data/lib/acts_as_list/version.rb +1 -1
- data/test/helper.rb +27 -1
- data/test/test_joined_list.rb +1 -12
- data/test/test_list.rb +2 -27
- data/test/test_no_update_for_extra_classes.rb +104 -0
- data/test/test_no_update_for_scope_destruction.rb +72 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4602fbf2208d5b39ba3a0fe78b4ab3ad0947e69a
|
4
|
+
data.tar.gz: f3ef72c6695c6441366c657f41a3d8b273e7c588
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 499b30c7a96fb04f2ab8c66414c7165686652b4969692a1e82a3af482b6f54e49d2270ed902466721874d0fcbe144cbc541fad09b55f22c385a0f181ffca8b3d
|
7
|
+
data.tar.gz: 38ae417b51053320bf227a3be9b44c8de46f754990bd4d74e427c47da6502e282e20c02ce4a47dc0466ee488c73fec14f8b44af660645379a412c9632ed2e29b
|
data/.travis.yml
CHANGED
@@ -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
data/CHANGELOG.md
CHANGED
@@ -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
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
|
data/gemfiles/rails_3_2.gemfile
CHANGED
data/gemfiles/rails_4_1.gemfile
CHANGED
data/gemfiles/rails_4_2.gemfile
CHANGED
data/gemfiles/rails_5_0.gemfile
CHANGED
@@ -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 => "../"
|
data/lib/acts_as_list.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'acts_as_list/active_record/acts/list'
|
2
|
-
require "acts_as_list/active_record/acts/
|
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:
|
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::
|
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 =
|
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
|
-
#
|
17
|
-
#
|
18
|
-
#
|
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
|
-
|
21
|
-
|
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(
|
27
|
-
|
86
|
+
def apply_to(klasses)
|
87
|
+
extracted_klasses.push(*klasses)
|
28
88
|
yield
|
29
89
|
ensure
|
30
|
-
|
90
|
+
extracted_klasses.clear
|
31
91
|
end
|
32
92
|
|
33
93
|
def applied_to?(klass)
|
34
|
-
|
94
|
+
extracted_klasses.any? { |k| k == klass }
|
35
95
|
end
|
36
96
|
|
37
97
|
private
|
38
98
|
|
39
|
-
def
|
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::
|
2
|
-
def self.call(caller_class,
|
3
|
-
caller_class
|
4
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
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(
|
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") }
|
data/lib/acts_as_list/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -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
|
data/test/test_joined_list.rb
CHANGED
@@ -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
|
-
|
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
|
data/test/test_list.rb
CHANGED
@@ -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.
|
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-
|
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
|