acts_as_list 0.7.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +5 -13
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/dependabot.yml +6 -0
  4. data/.github/workflows/ci.yml +123 -0
  5. data/.gitignore +1 -0
  6. data/.travis.yml +50 -12
  7. data/Appraisals +39 -6
  8. data/CHANGELOG.md +565 -148
  9. data/Gemfile +19 -14
  10. data/README.md +206 -19
  11. data/Rakefile +4 -4
  12. data/acts_as_list.gemspec +16 -11
  13. data/gemfiles/rails_4_2.gemfile +18 -9
  14. data/gemfiles/rails_5_0.gemfile +31 -0
  15. data/gemfiles/rails_5_1.gemfile +31 -0
  16. data/gemfiles/rails_5_2.gemfile +31 -0
  17. data/gemfiles/rails_6_0.gemfile +31 -0
  18. data/gemfiles/rails_6_1.gemfile +31 -0
  19. data/gemfiles/rails_7_0.gemfile +31 -0
  20. data/init.rb +2 -0
  21. data/lib/acts_as_list/active_record/acts/active_record.rb +5 -0
  22. data/lib/acts_as_list/active_record/acts/add_new_at_method_definer.rb +11 -0
  23. data/lib/acts_as_list/active_record/acts/aux_method_definer.rb +11 -0
  24. data/lib/acts_as_list/active_record/acts/callback_definer.rb +19 -0
  25. data/lib/acts_as_list/active_record/acts/list.rb +299 -306
  26. data/lib/acts_as_list/active_record/acts/no_update.rb +125 -0
  27. data/lib/acts_as_list/active_record/acts/position_column_method_definer.rb +101 -0
  28. data/lib/acts_as_list/active_record/acts/scope_method_definer.rb +77 -0
  29. data/lib/acts_as_list/active_record/acts/sequential_updates_method_definer.rb +28 -0
  30. data/lib/acts_as_list/active_record/acts/top_of_list_method_definer.rb +15 -0
  31. data/lib/acts_as_list/version.rb +3 -1
  32. data/lib/acts_as_list.rb +11 -14
  33. data/test/database.yml +18 -0
  34. data/test/helper.rb +50 -2
  35. data/test/shared.rb +3 -0
  36. data/test/shared_array_scope_list.rb +21 -4
  37. data/test/shared_list.rb +86 -12
  38. data/test/shared_list_sub.rb +63 -2
  39. data/test/shared_no_addition.rb +50 -2
  40. data/test/shared_quoting.rb +23 -0
  41. data/test/shared_top_addition.rb +36 -13
  42. data/test/shared_zero_based.rb +13 -0
  43. data/test/test_default_scope_with_select.rb +33 -0
  44. data/test/test_joined_list.rb +61 -0
  45. data/test/test_list.rb +601 -84
  46. data/test/test_no_update_for_extra_classes.rb +131 -0
  47. data/test/test_no_update_for_scope_destruction.rb +69 -0
  48. data/test/test_no_update_for_subclasses.rb +56 -0
  49. data/test/test_scope_with_user_defined_foreign_key.rb +42 -0
  50. metadata +56 -22
  51. data/gemfiles/rails_3_2.gemfile +0 -24
  52. data/gemfiles/rails_4_1.gemfile +0 -24
data/Gemfile CHANGED
@@ -1,23 +1,28 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem "sqlite3", platforms: [:ruby]
4
- gem "activerecord-jdbcsqlite3-adapter", platforms: [:jruby]
5
-
6
- platforms :rbx do
7
- gem "rubysl", "~> 2.0"
8
- gem "rubinius-developer_tools"
9
- gem "rubysl-test-unit"
10
- end
11
-
12
- # Specify your gem"s dependencies in acts_as_list-rails3.gemspec
13
3
  gemspec
14
4
 
15
5
  gem "rake"
16
6
  gem "appraisal"
17
- # Used to automatically generate changelog file
18
- gem "github_changelog_generator", "1.9.0"
7
+
8
+ group :development do
9
+ gem "github_changelog_generator", "1.9.0"
10
+ end
19
11
 
20
12
  group :test do
21
- gem "minitest", "~> 5.0"
22
- gem "test_after_commit", "~> 0.4.2"
13
+ gem "minitest", "~> 5.0"
14
+ gem "timecop"
15
+ gem "mocha"
16
+ end
17
+
18
+ group :sqlite do
19
+ gem "sqlite3", "~> 1.4"
20
+ end
21
+
22
+ group :postgresql do
23
+ gem "pg", "~> 1.2.0"
24
+ end
25
+
26
+ group :mysql do
27
+ gem "mysql2", "~> 0.5.0"
23
28
  end
data/README.md CHANGED
@@ -1,9 +1,20 @@
1
- # ActsAsList
1
+ # Acts As List
2
+
3
+ ## Build Status
4
+ [![Build Status](https://travis-ci.org/brendon/acts_as_list.svg?branch=master)](https://travis-ci.org/brendon/acts_as_list)
5
+ [![Gem Version](https://badge.fury.io/rb/acts_as_list.svg)](https://badge.fury.io/rb/acts_as_list)
2
6
 
3
7
  ## Description
4
8
 
5
9
  This `acts_as` extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a `position` column defined as an integer on the mapped database table.
6
10
 
11
+ ## 0.8.0 Upgrade Notes
12
+
13
+ There are a couple of changes of behaviour from `0.8.0` onwards:
14
+
15
+ - If you specify `add_new_at: :top`, new items will be added to the top of the list like always. But now, if you specify a position at insert time: `.create(position: 3)`, the position will be respected. In this example, the item will end up at position `3` and will move other items further down the list. Before `0.8.0` the position would be ignored and the item would still be added to the top of the list. [#220](https://github.com/brendon/acts_as_list/pull/220)
16
+ - `acts_as_list` now copes with disparate position integers (i.e. gaps between the numbers). There has been a change in behaviour for the `higher_items` method. It now returns items with the first item in the collection being the closest item to the reference item, and the last item in the collection being the furthest from the reference item (a.k.a. the first item in the list). [#223](https://github.com/brendon/acts_as_list/pull/223)
17
+
7
18
  ## Installation
8
19
 
9
20
  In your Gemfile:
@@ -20,27 +31,27 @@ At first, you need to add a `position` column to desired table:
20
31
 
21
32
  rails g migration AddPositionToTodoItem position:integer
22
33
  rake db:migrate
23
-
24
- After that you can use `acts_as_list` method in the model:
34
+
35
+ After that you can use `acts_as_list` method in the model:
25
36
 
26
37
  ```ruby
27
38
  class TodoList < ActiveRecord::Base
28
39
  has_many :todo_items, -> { order(position: :asc) }
29
40
  end
30
-
41
+
31
42
  class TodoItem < ActiveRecord::Base
32
43
  belongs_to :todo_list
33
44
  acts_as_list scope: :todo_list
34
45
  end
35
46
 
36
- todo_list = TodoList.find(...)
47
+ todo_list = TodoList.find(...)
37
48
  todo_list.todo_items.first.move_to_bottom
38
49
  todo_list.todo_items.last.move_higher
39
50
  ```
40
51
 
41
52
  ## Instance Methods Added To ActiveRecord Models
42
53
 
43
- You'll have a number of methods added to each instance of the ActiveRecord model that to which `acts_as_list` is added.
54
+ You'll have a number of methods added to each instance of the ActiveRecord model that to which `acts_as_list` is added.
44
55
 
45
56
  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.
46
57
 
@@ -70,9 +81,50 @@ In `acts_as_list`, "higher" means further up the list (a lower `position`), and
70
81
  - `list_item.lower_item`
71
82
  - `list_item.lower_items` will return all the items below `list_item` in the list (ordered by the position, ascending)
72
83
 
73
- ## Notes
74
- If the `position` column has a default value, then there is a slight change in behavior, i.e if you have 4 items in the list, and you insert 1, with a default position 0, it would be pushed to the bottom of the list. Please look at the tests for this and some recent pull requests for discussions related to this.
84
+ ## Adding `acts_as_list` To An Existing Model
85
+ As it stands `acts_as_list` requires position values to be set on the model before the instance methods above will work. Adding something like the below to your migration will set the default position. Change the parameters to order if you want a different initial ordering.
86
+
87
+ ```ruby
88
+ class AddPositionToTodoItem < ActiveRecord::Migration
89
+ def change
90
+ add_column :todo_items, :position, :integer
91
+ TodoItem.order(:updated_at).each.with_index(1) do |todo_item, index|
92
+ todo_item.update_column :position, index
93
+ end
94
+ end
95
+ end
96
+ ```
97
+
98
+ If you are using the scope option things can get a bit more complicated. Let's say you have `acts_as_list scope: :todo_list`, you might instead need something like this:
99
+
100
+ ```ruby
101
+ TodoList.all.each do |todo_list|
102
+ todo_list.todo_items.order(:updated_at).each.with_index(1) do |todo_item, index|
103
+ todo_item.update_column :position, index
104
+ end
105
+ end
106
+ ```
107
+
108
+ When using PostgreSQL, it is also possible to leave this migration up to the database layer. Inside of the `change` block you could write:
109
+
110
+ ```ruby
111
+ execute <<~SQL.squish
112
+ UPDATE todo_items
113
+ SET position = mapping.new_position
114
+ FROM (
115
+ SELECT
116
+ id,
117
+ ROW_NUMBER() OVER (
118
+ PARTITION BY todo_list_id
119
+ ORDER BY updated_at
120
+ ) as new_position
121
+ FROM todo_items
122
+ ) AS mapping
123
+ WHERE todo_items.id = mapping.id;
124
+ SQL
125
+ ```
75
126
 
127
+ ## Notes
76
128
  All `position` queries (select, update, etc.) inside gem methods are executed without the default scope (i.e. `Model.unscoped`), this will prevent nasty issues when the default scope is different from `acts_as_list` scope.
77
129
 
78
130
  The `position` column is set after validations are called, so you should not put a `presence` validation on the `position` column.
@@ -81,35 +133,170 @@ The `position` column is set after validations are called, so you should not put
81
133
  If you need a scope by a non-association field you should pass an array, containing field name, to a scope:
82
134
  ```ruby
83
135
  class TodoItem < ActiveRecord::Base
84
- # `kind` is a plain text field (e.g. 'work', 'shopping', 'meeting'), not an association
85
- acts_as_list scope: [:kind]
136
+ # `task_category` is a plain text field (e.g. 'work', 'shopping', 'meeting'), not an association
137
+ acts_as_list scope: [:task_category]
138
+ end
139
+ ```
140
+
141
+ You can also add multiple scopes in this fashion:
142
+ ```ruby
143
+ class TodoItem < ActiveRecord::Base
144
+ belongs_to :todo_list
145
+ acts_as_list scope: [:task_category, :todo_list_id]
146
+ end
147
+ ```
148
+
149
+ Furthermore, you can optionally include a hash of fixed parameters that will be included in all queries:
150
+ ```ruby
151
+ class TodoItem < ActiveRecord::Base
152
+ belongs_to :todo_list
153
+ # or `discarded_at` if using discard
154
+ acts_as_list scope: [:task_category, :todo_list_id, deleted_at: nil]
86
155
  end
87
156
  ```
88
157
 
158
+ This is useful when using this gem in conjunction with the popular [acts_as_paranoid](https://github.com/ActsAsParanoid/acts_as_paranoid) or [discard](https://github.com/jhawthorn/discard) gems.
159
+
89
160
  ## More Options
90
161
  - `column`
91
- default: 'position'. Use this option if the column name in your database is different from position.
162
+ default: `position`. Use this option if the column name in your database is different from position.
92
163
  - `top_of_list`
93
- default: '1'. Use this option to define the top of the list. Use 0 to make the collection act more like an array in its indexing.
164
+ default: `1`. Use this option to define the top of the list. Use 0 to make the collection act more like an array in its indexing.
94
165
  - `add_new_at`
95
- default: ':bottom'. Use this option to specify whether objects get added to the :top or :bottom of the list. `nil` will result in new items not being added to the list on create, i.e, position will be kept nil after create.
166
+ default: `:bottom`. Use this option to specify whether objects get added to the `:top` or `:bottom` of the list. `nil` will result in new items not being added to the list on create, i.e, position will be kept nil after create.
167
+ - `touch_on_update`
168
+ default: `true`. Use `touch_on_update: false` if you don't want to update the timestamps of the associated records.
169
+ - `sequential_updates`
170
+ Specifies whether insert_at should update objects positions during shuffling one by one to respect position column unique not null constraint. Defaults to true if position column has unique index, otherwise false. If constraint is `deferrable initially deferred` (PostgreSQL), overriding it with false will speed up insert_at.
171
+
172
+ ## Disabling temporarily
173
+
174
+ If you need to temporarily disable `acts_as_list` during specific operations such as mass-update or imports:
175
+ ```ruby
176
+ TodoItem.acts_as_list_no_update do
177
+ perform_mass_update
178
+ end
179
+ ```
180
+ In an `acts_as_list_no_update` block, all callbacks are disabled, and positions are not updated. New records will be created with
181
+ the default value from the database. It is your responsibility to correctly manage `positions` values.
182
+
183
+ 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.
184
+ ```ruby
185
+ class TodoList < ActiveRecord::Base
186
+ has_many :todo_items, -> { order(position: :asc) }
187
+ acts_as_list
188
+ end
189
+
190
+ class TodoItem < ActiveRecord::Base
191
+ belongs_to :todo_list
192
+ has_many :todo_attachments, -> { order(position: :asc) }
193
+
194
+ acts_as_list scope: :todo_list
195
+ end
196
+
197
+ class TodoAttachment < ActiveRecord::Base
198
+ belongs_to :todo_list
199
+ acts_as_list scope: :todo_item
200
+ end
201
+
202
+ TodoItem.acts_as_list_no_update([TodoAttachment]) do
203
+ TodoItem.find(10).update(position: 2)
204
+ TodoAttachment.find(10).update(position: 1)
205
+ TodoAttachment.find(11).update(position: 2)
206
+ TodoList.find(2).update(position: 3) # For this instance the callbacks will be called because we haven't passed the class as an argument
207
+ end
208
+ ```
209
+
210
+ ## Troubleshooting Database Deadlock Errors
211
+ When using this gem in an app with a high amount of concurrency, you may see "deadlock" errors raised by your database server.
212
+ It's difficult for the gem to provide a solution that fits every app.
213
+ Here are some steps you can take to mitigate and handle these kinds of errors.
214
+
215
+ ### 1) Use the Most Concise API
216
+ One easy way to reduce deadlocks is to use the most concise gem API available for what you want to accomplish.
217
+ In this specific example, the more concise API for creating a list item at a position results in one transaction instead of two,
218
+ and it issues fewer SQL statements. Issuing fewer statements tends to lead to faster transactions.
219
+ Faster transactions are less likely to deadlock.
220
+
221
+ Example:
222
+ ```ruby
223
+ # Good
224
+ TodoItem.create(todo_list: todo_list, position: 1)
225
+
226
+ # Bad
227
+ item = TodoItem.create(todo_list: todo_list)
228
+ item.insert_at(1)
229
+ ```
230
+
231
+ ### 2) Rescue then Retry
232
+ Deadlocks are always a possibility when updating tables rows concurrently.
233
+ The general advice from MySQL documentation is to catch these errors and simply retry the transaction; it will probably succeed on another attempt. (see [How to Minimize and Handle Deadlocks](https://dev.mysql.com/doc/refman/8.0/en/innodb-deadlocks-handling.html))
234
+ Retrying transactions sounds simple, but there are many details that need to be chosen on a per-app basis:
235
+ How many retry attempts should be made?
236
+ Should there be a wait time between attempts?
237
+ What _other_ statements were in the transaction that got rolled back?
238
+
239
+ Here a simple example of rescuing from deadlock and retrying the operation:
240
+ * `ActiveRecord::Deadlocked` is available in Rails >= 5.1.0.
241
+ * If you have Rails < 5.1.0, you will need to rescue `ActiveRecord::StatementInvalid` and check `#cause`.
242
+ ```ruby
243
+ attempts_left = 2
244
+ while attempts_left > 0
245
+ attempts_left -= 1
246
+ begin
247
+ TodoItem.transaction do
248
+ TodoItem.create(todo_list: todo_list, position: 1)
249
+ end
250
+ attempts_left = 0
251
+ rescue ActiveRecord::Deadlocked
252
+ raise unless attempts_left > 0
253
+ end
254
+ end
255
+ ```
256
+
257
+ You can also use the approach suggested in this StackOverflow post:
258
+ https://stackoverflow.com/questions/4027659/activerecord3-deadlock-retry
259
+
260
+ ### 3) Lock Parent Record
261
+ In addition to reacting to deadlocks, it is possible to reduce their frequency with more pessimistic locking.
262
+ This approach uses the parent record as a mutex for the entire list.
263
+ This kind of locking is very effective at reducing the frequency of deadlocks while updating list items.
264
+ However, there are some things to keep in mind:
265
+ * This locking pattern needs to be used around *every* call that modifies the list; even if it does not reorder list items.
266
+ * This locking pattern effectively serializes operations on the list. The throughput of operations on the list will decrease.
267
+ * Locking the parent record may lead to deadlock elsewhere if some other code also locks the parent table.
268
+
269
+ Example:
270
+ ```ruby
271
+ todo_list = TodoList.create(name: "The List")
272
+ todo_list.with_lock do
273
+ item = TodoItem.create(description: "Buy Groceries", todo_list: todo_list, position: 1)
274
+ end
275
+ ```
96
276
 
97
277
  ## Versions
278
+ Version `0.9.0` adds `acts_as_list_no_update` (https://github.com/brendon/acts_as_list/pull/244) and compatibility with not-null and uniqueness constraints on the database (https://github.com/brendon/acts_as_list/pull/246). These additions shouldn't break compatibility with existing implementations.
279
+
280
+ As of version `0.7.5` Rails 5 is supported.
281
+
98
282
  All versions `0.1.5` onwards require Rails 3.0.x and higher.
99
283
 
100
- ## Build Status
101
- [![Build Status](https://secure.travis-ci.org/swanandp/acts_as_list.png)](https://secure.travis-ci.org/swanandp/acts_as_list)
284
+ ## A note about data integrity
285
+
286
+ We often hear complaints that `position` values are repeated, incorrect etc. For example, #254. To ensure data integrity, you should rely on your database. There are two things you can do:
287
+
288
+ 1. Use constraints. If you model `Item` that `belongs_to` an `Order`, and it has a `position` column, then add a unique constraint on `items` with `[:order_id, :position]`. Think of it as a list invariant. What are the properties of your list that don't change no matter how many items you have in it? One such propery is that each item has a distinct position. Another _could be_ that position is always greater than 0. It is strongly recommended that you rely on your database to enforce these invariants or constraints. Here are the docs for [PostgreSQL](https://www.postgresql.org/docs/9.5/static/ddl-constraints.html) and [MySQL](https://dev.mysql.com/doc/refman/8.0/en/alter-table.html).
289
+ 2. Use mutexes or row level locks. At its heart the duplicate problem is that of handling concurrency. Adding a contention resolution mechanism like locks will solve it to some extent. But it is not a solution or replacement for constraints. Locks are also prone to deadlocks.
290
+
291
+ As a library, `acts_as_list` may not always have all the context needed to apply these tools. They are much better suited at the application level.
102
292
 
103
- ## Workflow Status
104
- [![WIP Issues](https://badge.waffle.io/swanandp/acts_as_list.png)](http://waffle.io/swanandp/acts_as_list)
105
293
 
106
294
  ## Roadmap
107
295
 
108
296
  1. Sort based feature
109
- 2. Rails 4 compatibility and bye bye Rails 2! Older versions would of course continue to work with Rails 2, but there won't be any support on those.
110
297
 
111
298
  ## Contributing to `acts_as_list`
112
-
299
+
113
300
  - Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
114
301
  - Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
115
302
  - Fork the project
data/Rakefile CHANGED
@@ -10,8 +10,8 @@ task default: :test
10
10
 
11
11
  desc "Test the acts_as_list plugin."
12
12
  Rake::TestTask.new(:test) do |t|
13
- t.libs << "lib" << "test"
14
- t.pattern = "test/**/test_*.rb"
13
+ t.libs << "test" << "."
14
+ t.test_files = Rake::FileList["test/**/test_*.rb"]
15
15
  t.verbose = false
16
16
  end
17
17
 
@@ -38,5 +38,5 @@ end
38
38
  require 'github_changelog_generator/task'
39
39
  GitHubChangelogGenerator::RakeTask.new :changelog do |config|
40
40
  config.project = 'acts_as_list'
41
- config.user = 'swanandp'
42
- end
41
+ config.user = 'brendon'
42
+ end
data/acts_as_list.gemspec CHANGED
@@ -7,23 +7,28 @@ Gem::Specification.new do |s|
7
7
  s.name = "acts_as_list"
8
8
  s.version = ActiveRecord::Acts::List::VERSION
9
9
  s.platform = Gem::Platform::RUBY
10
- s.authors = ["David Heinemeier Hansson", "Swanand Pagnis", "Quinn Chaffee"]
11
- s.email = ["swanand.pagnis@gmail.com"]
12
- s.homepage = "http://github.com/swanandp/acts_as_list"
10
+ s.authors = ["Swanand Pagnis", "Brendon Muir"]
11
+ s.email = %w(swanand.pagnis@gmail.com brendon@spikeatschool.co.nz)
12
+ s.homepage = "http://github.com/brendon/acts_as_list"
13
13
  s.summary = "A gem adding sorting, reordering capabilities to an active_record model, allowing it to act as a list"
14
14
  s.description = 'This "acts_as" extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a "position" column defined as an integer on the mapped database table.'
15
15
  s.license = "MIT"
16
- s.rubyforge_project = "acts_as_list"
17
- s.required_ruby_version = ">= 1.9.2"
16
+ s.required_ruby_version = ">= 2.4.7"
17
+
18
+ if s.respond_to?(:metadata)
19
+ s.metadata['changelog_uri'] = 'https://github.com/brendon/acts_as_list/blob/master/CHANGELOG.md'
20
+ s.metadata['source_code_uri'] = 'https://github.com/brendon/acts_as_list'
21
+ s.metadata['bug_tracker_uri'] = 'https://github.com/brendon/acts_as_list/issues'
22
+ end
18
23
 
19
24
  # Load Paths...
20
- s.files = `git ls-files`.split("\n")
21
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
- s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
23
- s.require_paths = ["lib"]
25
+ s.files = `git ls-files`.split("\n")
26
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
27
+ s.executables = `git ls-files -- bin/*`.split("\n").map {|f| File.basename(f)}
28
+ s.require_paths = ["lib"]
24
29
 
25
30
 
26
31
  # Dependencies (installed via "bundle install")
27
- s.add_dependency("activerecord", [">= 3.0"])
28
- s.add_development_dependency("bundler", [">= 1.0.0"])
32
+ s.add_dependency "activerecord", ">= 4.2"
33
+ s.add_development_dependency "bundler", ">= 1.0.0"
29
34
  end
@@ -2,22 +2,31 @@
2
2
 
3
3
  source "http://rubygems.org"
4
4
 
5
- gem "sqlite3", :platforms => [:ruby]
6
- gem "activerecord-jdbcsqlite3-adapter", :platforms => [:jruby]
7
5
  gem "rake"
8
6
  gem "appraisal"
9
- gem "github_changelog_generator", "1.9.0"
10
- gem "activerecord", "~> 4.2.1"
7
+ gem "activerecord", "~> 4.2.0"
8
+
9
+ group :development do
10
+ gem "github_changelog_generator", "1.9.0"
11
+ end
11
12
 
12
13
  group :test do
13
14
  gem "minitest", "~> 5.0"
15
+ gem "timecop"
16
+ gem "mocha"
14
17
  gem "test_after_commit", "~> 0.4.2"
15
18
  end
16
19
 
17
- platforms :rbx do
18
- gem "rubysl", "~> 2.0"
19
- gem "rubinius-developer_tools"
20
- gem "rubysl-test-unit"
20
+ group :sqlite do
21
+ gem "sqlite3", "~> 1.3.13"
22
+ end
23
+
24
+ group :postgresql do
25
+ gem "pg", "~> 0.18.4"
26
+ end
27
+
28
+ group :mysql do
29
+ gem "mysql2", "~> 0.4.0"
21
30
  end
22
31
 
23
- gemspec :path => "../"
32
+ gemspec path: "../"
@@ -0,0 +1,31 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "appraisal"
7
+ gem "activerecord", "~> 5.0.0"
8
+
9
+ group :development do
10
+ gem "github_changelog_generator", "1.9.0"
11
+ end
12
+
13
+ group :test do
14
+ gem "minitest", "~> 5.0"
15
+ gem "timecop"
16
+ gem "mocha"
17
+ end
18
+
19
+ group :sqlite do
20
+ gem "sqlite3", "~> 1.3.13"
21
+ end
22
+
23
+ group :postgresql do
24
+ gem "pg", "~> 1.2.0"
25
+ end
26
+
27
+ group :mysql do
28
+ gem "mysql2", "~> 0.5.0"
29
+ end
30
+
31
+ gemspec path: "../"
@@ -0,0 +1,31 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "appraisal"
7
+ gem "activerecord", "~> 5.1.0"
8
+
9
+ group :development do
10
+ gem "github_changelog_generator", "1.9.0"
11
+ end
12
+
13
+ group :test do
14
+ gem "minitest", "~> 5.0"
15
+ gem "timecop"
16
+ gem "mocha"
17
+ end
18
+
19
+ group :sqlite do
20
+ gem "sqlite3", "~> 1.4"
21
+ end
22
+
23
+ group :postgresql do
24
+ gem "pg", "~> 1.2.0"
25
+ end
26
+
27
+ group :mysql do
28
+ gem "mysql2", "~> 0.5.0"
29
+ end
30
+
31
+ gemspec path: "../"
@@ -0,0 +1,31 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "appraisal"
7
+ gem "activerecord", "~> 5.2.0"
8
+
9
+ group :development do
10
+ gem "github_changelog_generator", "1.9.0"
11
+ end
12
+
13
+ group :test do
14
+ gem "minitest", "~> 5.0"
15
+ gem "timecop"
16
+ gem "mocha"
17
+ end
18
+
19
+ group :sqlite do
20
+ gem "sqlite3", "~> 1.4"
21
+ end
22
+
23
+ group :postgresql do
24
+ gem "pg", "~> 1.2.0"
25
+ end
26
+
27
+ group :mysql do
28
+ gem "mysql2", "~> 0.5.0"
29
+ end
30
+
31
+ gemspec path: "../"
@@ -0,0 +1,31 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "appraisal"
7
+ gem "activerecord", "~> 6.0.0"
8
+
9
+ group :development do
10
+ gem "github_changelog_generator", "1.9.0"
11
+ end
12
+
13
+ group :test do
14
+ gem "minitest", "~> 5.0"
15
+ gem "timecop"
16
+ gem "mocha"
17
+ end
18
+
19
+ group :sqlite do
20
+ gem "sqlite3", "~> 1.4"
21
+ end
22
+
23
+ group :postgresql do
24
+ gem "pg", "~> 1.2.0"
25
+ end
26
+
27
+ group :mysql do
28
+ gem "mysql2", "~> 0.5.0"
29
+ end
30
+
31
+ gemspec path: "../"
@@ -0,0 +1,31 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "appraisal"
7
+ gem "activerecord", "~> 6.1.0"
8
+
9
+ group :development do
10
+ gem "github_changelog_generator", "1.9.0"
11
+ end
12
+
13
+ group :test do
14
+ gem "minitest", "~> 5.0"
15
+ gem "timecop"
16
+ gem "mocha"
17
+ end
18
+
19
+ group :sqlite do
20
+ gem "sqlite3", "~> 1.4"
21
+ end
22
+
23
+ group :postgresql do
24
+ gem "pg", "~> 1.2.0"
25
+ end
26
+
27
+ group :mysql do
28
+ gem "mysql2", "~> 0.5.0"
29
+ end
30
+
31
+ gemspec path: "../"
@@ -0,0 +1,31 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "appraisal"
7
+ gem "activerecord", "~> 7.0.0"
8
+
9
+ group :development do
10
+ gem "github_changelog_generator", "~> 1.16.0"
11
+ end
12
+
13
+ group :test do
14
+ gem "minitest", "~> 5.0"
15
+ gem "timecop"
16
+ gem "mocha"
17
+ end
18
+
19
+ group :sqlite do
20
+ gem "sqlite3", "~> 1.4"
21
+ end
22
+
23
+ group :postgresql do
24
+ gem "pg", "~> 1.3.0"
25
+ end
26
+
27
+ group :mysql do
28
+ gem "mysql2", "~> 0.5.0"
29
+ end
30
+
31
+ gemspec path: "../"
data/init.rb CHANGED
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  $:.unshift "#{File.dirname(__FILE__)}/lib"
2
4
  require "acts_as_list"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveSupport.on_load :active_record do
4
+ extend ActiveRecord::Acts::List::ClassMethods
5
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord::Acts::List::AddNewAtMethodDefiner #:nodoc:
4
+ def self.call(caller_class, add_new_at)
5
+ caller_class.class_eval do
6
+ define_method :add_new_at do
7
+ add_new_at
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord::Acts::List::AuxMethodDefiner #:nodoc:
4
+ def self.call(caller_class)
5
+ caller_class.class_eval do
6
+ define_method :acts_as_list_class do
7
+ caller_class
8
+ end
9
+ end
10
+ end
11
+ end