acts_as_list 0.1.4 → 0.2.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.
- data/.gitignore +3 -0
- data/.travis.yml +6 -0
- data/Gemfile +2 -0
- data/README.md +103 -0
- data/Rakefile +1 -3
- data/acts_as_list.gemspec +2 -2
- data/init.rb +2 -0
- data/lib/acts_as_list/active_record/acts/list.rb +179 -36
- data/lib/acts_as_list/version.rb +1 -1
- data/lib/acts_as_list.rb +23 -1
- data/test/helper.rb +2 -0
- data/test/shared.rb +8 -0
- data/test/shared_array_scope_list.rb +160 -0
- data/test/shared_list.rb +230 -0
- data/test/shared_list_sub.rb +122 -0
- data/test/shared_top_addition.rb +87 -0
- data/test/shared_zero_based.rb +86 -0
- data/test/test_list.rb +291 -465
- metadata +32 -23
- data/README.rdoc +0 -35
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# ActsAsList
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
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
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
In your Gemfile:
|
|
10
|
+
|
|
11
|
+
gem 'acts_as_list'
|
|
12
|
+
|
|
13
|
+
Or, from the command line:
|
|
14
|
+
|
|
15
|
+
gem install acts_as_list
|
|
16
|
+
|
|
17
|
+
## Example
|
|
18
|
+
|
|
19
|
+
At first, you need to add a `position` column to desired table:
|
|
20
|
+
|
|
21
|
+
rails g migration AddPositionToTodoItem position:integer
|
|
22
|
+
rake db:migrate
|
|
23
|
+
|
|
24
|
+
After that you can use `acts_as_list` method in the model:
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
class TodoList < ActiveRecord::Base
|
|
28
|
+
has_many :todo_items, order: :position
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class TodoItem < ActiveRecord::Base
|
|
32
|
+
belongs_to :todo_list
|
|
33
|
+
acts_as_list scope: :todo_list
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
todo_list.first.move_to_bottom
|
|
37
|
+
todo_list.last.move_higher
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Instance Methods Added To ActiveRecord Models
|
|
41
|
+
|
|
42
|
+
You'll have a number of methods added to each instance of the ActiveRecord model that to which `acts_as_list` is added.
|
|
43
|
+
|
|
44
|
+
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.
|
|
45
|
+
|
|
46
|
+
### Methods That Change Position and Reorder List
|
|
47
|
+
|
|
48
|
+
- `list_item.insert_at(2)`
|
|
49
|
+
- `list_item.move_lower` will do nothing if the item is the lowest item
|
|
50
|
+
- `list_item.move_higher` will do nothing if the item is the highest item
|
|
51
|
+
- `list_item.move_to_bottom`
|
|
52
|
+
- `list_item.move_to_top`
|
|
53
|
+
- `list_item.remove_from_list`
|
|
54
|
+
|
|
55
|
+
### Methods That Change Position Without Reordering List
|
|
56
|
+
|
|
57
|
+
- `list_item.increment_position`
|
|
58
|
+
- `list_item.decrement_position`
|
|
59
|
+
- `list_item.set_list_position(3)`
|
|
60
|
+
|
|
61
|
+
### Methods That Return Attributes of the Item's List Position
|
|
62
|
+
- `list_item.first?`
|
|
63
|
+
- `list_item.last?`
|
|
64
|
+
- `list_item.in_list?`
|
|
65
|
+
- `list_item.not_in_list?`
|
|
66
|
+
- `list_item.default_position?`
|
|
67
|
+
- `list_item.higher_item`
|
|
68
|
+
- `list_item.higher_items` will return all the items above `list_item` in the list (ordered by the position, ascending)
|
|
69
|
+
- `list_item.lower_item`
|
|
70
|
+
- `list_item.lower_items` will return all the items below `list_item` in the list (ordered by the position, ascending)
|
|
71
|
+
|
|
72
|
+
## Notes
|
|
73
|
+
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.
|
|
74
|
+
|
|
75
|
+
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.
|
|
76
|
+
|
|
77
|
+
The `position` column is set after validations are called, so you should not put a `presence` validation on the `position` column.
|
|
78
|
+
|
|
79
|
+
## Versions
|
|
80
|
+
All versions `0.1.5` onwards require Rails 3.0.x and higher.
|
|
81
|
+
|
|
82
|
+
## Build Status
|
|
83
|
+
[](https://secure.travis-ci.org/swanandp/acts_as_list)
|
|
84
|
+
|
|
85
|
+
## Roadmap
|
|
86
|
+
|
|
87
|
+
1. Sort based feature
|
|
88
|
+
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.
|
|
89
|
+
|
|
90
|
+
## Contributing to `acts_as_list`
|
|
91
|
+
|
|
92
|
+
- Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
|
93
|
+
- Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
|
94
|
+
- Fork the project
|
|
95
|
+
- Start a feature/bugfix branch
|
|
96
|
+
- Commit and push until you are happy with your contribution
|
|
97
|
+
- Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
|
98
|
+
- Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
|
99
|
+
- I would recommend using Rails 3.1.x and higher for testing the build before a pull request. The current test harness does not quite work with 3.0.x. The plugin itself works, but the issue lies with testing infrastructure.
|
|
100
|
+
|
|
101
|
+
## Copyright
|
|
102
|
+
|
|
103
|
+
Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
|
data/Rakefile
CHANGED
|
@@ -12,11 +12,9 @@ desc 'Test the acts_as_list plugin.'
|
|
|
12
12
|
Rake::TestTask.new(:test) do |t|
|
|
13
13
|
t.libs << 'lib' << 'test'
|
|
14
14
|
t.pattern = 'test/**/test_*.rb'
|
|
15
|
-
t.verbose =
|
|
15
|
+
t.verbose = false
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
18
|
# Run the rdoc task to generate rdocs for this gem
|
|
21
19
|
require 'rdoc/task'
|
|
22
20
|
RDoc::Task.new do |rdoc|
|
data/acts_as_list.gemspec
CHANGED
|
@@ -24,8 +24,8 @@ Gem::Specification.new do |s|
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
# Dependencies (installed via 'bundle install')...
|
|
27
|
-
s.
|
|
28
|
-
s.add_development_dependency("
|
|
27
|
+
s.add_dependency("activerecord", [">= 3.0"])
|
|
28
|
+
s.add_development_dependency("bundler", [">= 1.0.0"])
|
|
29
29
|
s.add_development_dependency("rdoc")
|
|
30
30
|
s.add_development_dependency("sqlite3")
|
|
31
31
|
end
|
data/init.rb
CHANGED
|
@@ -26,14 +26,15 @@ module ActiveRecord
|
|
|
26
26
|
# Configuration options are:
|
|
27
27
|
#
|
|
28
28
|
# * +column+ - specifies the column name to use for keeping the position integer (default: +position+)
|
|
29
|
-
# * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach <tt>_id</tt>
|
|
30
|
-
# (if it hasn't already been added) and use that as the foreign key restriction. It's also possible
|
|
29
|
+
# * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach <tt>_id</tt>
|
|
30
|
+
# (if it hasn't already been added) and use that as the foreign key restriction. It's also possible
|
|
31
31
|
# to give it an entire string that is interpolated if you need a tighter scope than just a foreign key.
|
|
32
32
|
# Example: <tt>acts_as_list :scope => 'todo_list_id = #{todo_list_id} AND completed = 0'</tt>
|
|
33
33
|
# * +top_of_list+ - defines the integer used for the top of the list. Defaults to 1. Use 0 to make the collection
|
|
34
|
-
# act more
|
|
34
|
+
# act more like an array in its indexing.
|
|
35
|
+
# * +add_new_at+ - specifies whether objects get added to the :top or :bottom of the list. (default: +bottom+)
|
|
35
36
|
def acts_as_list(options = {})
|
|
36
|
-
configuration = { :column => "position", :scope => "1 = 1", :top_of_list => 1}
|
|
37
|
+
configuration = { :column => "position", :scope => "1 = 1", :top_of_list => 1, :add_new_at => :bottom}
|
|
37
38
|
configuration.update(options) if options.is_a?(Hash)
|
|
38
39
|
|
|
39
40
|
configuration[:scope] = "#{configuration[:scope]}_id".intern if configuration[:scope].is_a?(Symbol) && configuration[:scope].to_s !~ /_id$/
|
|
@@ -47,7 +48,7 @@ module ActiveRecord
|
|
|
47
48
|
elsif configuration[:scope].is_a?(Array)
|
|
48
49
|
scope_condition_method = %(
|
|
49
50
|
def scope_condition
|
|
50
|
-
attrs = %w(#{configuration[:scope].join(" ")}).inject({}) do |memo,column|
|
|
51
|
+
attrs = %w(#{configuration[:scope].join(" ")}).inject({}) do |memo,column|
|
|
51
52
|
memo[column.intern] = send(column.intern); memo
|
|
52
53
|
end
|
|
53
54
|
self.class.send(:sanitize_sql_hash_for_conditions, attrs)
|
|
@@ -58,7 +59,7 @@ module ActiveRecord
|
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
class_eval <<-EOV
|
|
61
|
-
include ActiveRecord::Acts::List::InstanceMethods
|
|
62
|
+
include ::ActiveRecord::Acts::List::InstanceMethods
|
|
62
63
|
|
|
63
64
|
def acts_as_list_top
|
|
64
65
|
#{configuration[:top_of_list]}.to_i
|
|
@@ -72,10 +73,28 @@ module ActiveRecord
|
|
|
72
73
|
'#{configuration[:column]}'
|
|
73
74
|
end
|
|
74
75
|
|
|
76
|
+
def scope_name
|
|
77
|
+
'#{configuration[:scope]}'
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def add_new_at
|
|
81
|
+
'#{configuration[:add_new_at]}'
|
|
82
|
+
end
|
|
83
|
+
|
|
75
84
|
#{scope_condition_method}
|
|
76
85
|
|
|
77
|
-
|
|
78
|
-
|
|
86
|
+
# only add to attr_accessible
|
|
87
|
+
# if the class has some mass_assignment_protection
|
|
88
|
+
|
|
89
|
+
if defined?(accessible_attributes) and !accessible_attributes.blank?
|
|
90
|
+
attr_accessible :#{configuration[:column]}
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
before_destroy :reload_position
|
|
94
|
+
after_destroy :decrement_positions_on_lower_items
|
|
95
|
+
before_create :add_to_list_#{configuration[:add_new_at]}
|
|
96
|
+
after_update :update_positions
|
|
97
|
+
before_update :check_scope
|
|
79
98
|
EOV
|
|
80
99
|
end
|
|
81
100
|
end
|
|
@@ -134,20 +153,20 @@ module ActiveRecord
|
|
|
134
153
|
def remove_from_list
|
|
135
154
|
if in_list?
|
|
136
155
|
decrement_positions_on_lower_items
|
|
137
|
-
|
|
156
|
+
set_list_position(nil)
|
|
138
157
|
end
|
|
139
158
|
end
|
|
140
159
|
|
|
141
160
|
# Increase the position of this item without adjusting the rest of the list.
|
|
142
161
|
def increment_position
|
|
143
162
|
return unless in_list?
|
|
144
|
-
|
|
163
|
+
set_list_position(self.send(position_column).to_i + 1)
|
|
145
164
|
end
|
|
146
165
|
|
|
147
166
|
# Decrease the position of this item without adjusting the rest of the list.
|
|
148
167
|
def decrement_position
|
|
149
168
|
return unless in_list?
|
|
150
|
-
|
|
169
|
+
set_list_position(self.send(position_column).to_i - 1)
|
|
151
170
|
end
|
|
152
171
|
|
|
153
172
|
# Return +true+ if this object is the first in the list.
|
|
@@ -165,31 +184,81 @@ module ActiveRecord
|
|
|
165
184
|
# Return the next higher item in the list.
|
|
166
185
|
def higher_item
|
|
167
186
|
return nil unless in_list?
|
|
168
|
-
acts_as_list_class.find(:first, :conditions =>
|
|
169
|
-
"#{scope_condition} AND #{position_column}
|
|
187
|
+
acts_as_list_class.unscoped.find(:first, :conditions =>
|
|
188
|
+
"#{scope_condition} AND #{position_column} < #{(send(position_column).to_i).to_s}",
|
|
189
|
+
:order => "#{acts_as_list_class.table_name}.#{position_column} DESC"
|
|
170
190
|
)
|
|
171
191
|
end
|
|
172
192
|
|
|
193
|
+
# Return the next n higher items in the list
|
|
194
|
+
# selects all higher items by default
|
|
195
|
+
def higher_items(limit=nil)
|
|
196
|
+
limit ||= acts_as_list_list.count
|
|
197
|
+
position_value = send(position_column)
|
|
198
|
+
acts_as_list_list.
|
|
199
|
+
where("#{position_column} < ?", position_value).
|
|
200
|
+
where("#{position_column} >= ?", position_value - limit).
|
|
201
|
+
limit(limit).
|
|
202
|
+
order("#{acts_as_list_class.table_name}.#{position_column} ASC")
|
|
203
|
+
end
|
|
204
|
+
|
|
173
205
|
# Return the next lower item in the list.
|
|
174
206
|
def lower_item
|
|
175
207
|
return nil unless in_list?
|
|
176
|
-
acts_as_list_class.find(:first, :conditions =>
|
|
177
|
-
"#{scope_condition} AND #{position_column}
|
|
208
|
+
acts_as_list_class.unscoped.find(:first, :conditions =>
|
|
209
|
+
"#{scope_condition} AND #{position_column} > #{(send(position_column).to_i).to_s}",
|
|
210
|
+
:order => "#{acts_as_list_class.table_name}.#{position_column} ASC"
|
|
178
211
|
)
|
|
179
212
|
end
|
|
180
213
|
|
|
214
|
+
# Return the next n lower items in the list
|
|
215
|
+
# selects all lower items by default
|
|
216
|
+
def lower_items(limit=nil)
|
|
217
|
+
limit ||= acts_as_list_list.count
|
|
218
|
+
position_value = send(position_column)
|
|
219
|
+
acts_as_list_list.
|
|
220
|
+
where("#{position_column} > ?", position_value).
|
|
221
|
+
where("#{position_column} <= ?", position_value + limit).
|
|
222
|
+
limit(limit).
|
|
223
|
+
order("#{acts_as_list_class.table_name}.#{position_column} ASC")
|
|
224
|
+
end
|
|
225
|
+
|
|
181
226
|
# Test if this record is in a list
|
|
182
227
|
def in_list?
|
|
183
|
-
!
|
|
228
|
+
!not_in_list?
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def not_in_list?
|
|
232
|
+
send(position_column).nil?
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def default_position
|
|
236
|
+
acts_as_list_class.columns_hash[position_column.to_s].default
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def default_position?
|
|
240
|
+
default_position == send(position_column)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Sets the new position and saves it
|
|
244
|
+
def set_list_position(new_position)
|
|
245
|
+
send("#{position_column}=", new_position)
|
|
246
|
+
save!
|
|
184
247
|
end
|
|
185
248
|
|
|
186
249
|
private
|
|
250
|
+
def acts_as_list_list
|
|
251
|
+
acts_as_list_class.unscoped.
|
|
252
|
+
where(scope_condition)
|
|
253
|
+
end
|
|
254
|
+
|
|
187
255
|
def add_to_list_top
|
|
188
256
|
increment_positions_on_all_items
|
|
257
|
+
self[position_column] = acts_as_list_top
|
|
189
258
|
end
|
|
190
259
|
|
|
191
260
|
def add_to_list_bottom
|
|
192
|
-
if
|
|
261
|
+
if not_in_list? || default_position?
|
|
193
262
|
self[position_column] = bottom_position_in_list.to_i + 1
|
|
194
263
|
else
|
|
195
264
|
increment_positions_on_lower_items(self[position_column])
|
|
@@ -210,62 +279,136 @@ module ActiveRecord
|
|
|
210
279
|
def bottom_item(except = nil)
|
|
211
280
|
conditions = scope_condition
|
|
212
281
|
conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" if except
|
|
213
|
-
acts_as_list_class.
|
|
282
|
+
acts_as_list_class.unscoped.where(conditions).order("#{acts_as_list_class.table_name}.#{position_column} DESC").first
|
|
214
283
|
end
|
|
215
284
|
|
|
216
285
|
# Forces item to assume the bottom position in the list.
|
|
217
286
|
def assume_bottom_position
|
|
218
|
-
|
|
287
|
+
set_list_position(bottom_position_in_list(self).to_i + 1)
|
|
219
288
|
end
|
|
220
289
|
|
|
221
290
|
# Forces item to assume the top position in the list.
|
|
222
291
|
def assume_top_position
|
|
223
|
-
|
|
292
|
+
set_list_position(acts_as_list_top)
|
|
224
293
|
end
|
|
225
294
|
|
|
226
295
|
# This has the effect of moving all the higher items up one.
|
|
227
296
|
def decrement_positions_on_higher_items(position)
|
|
228
|
-
acts_as_list_class.
|
|
229
|
-
"#{
|
|
297
|
+
acts_as_list_class.unscoped.where(
|
|
298
|
+
"#{scope_condition} AND #{position_column} <= #{position}"
|
|
299
|
+
).update_all(
|
|
300
|
+
"#{position_column} = (#{position_column} - 1)"
|
|
230
301
|
)
|
|
231
302
|
end
|
|
232
303
|
|
|
233
304
|
# This has the effect of moving all the lower items up one.
|
|
234
|
-
def decrement_positions_on_lower_items
|
|
305
|
+
def decrement_positions_on_lower_items(position=nil)
|
|
235
306
|
return unless in_list?
|
|
236
|
-
|
|
237
|
-
|
|
307
|
+
position ||= send(position_column).to_i
|
|
308
|
+
acts_as_list_class.unscoped.where(
|
|
309
|
+
"#{scope_condition} AND #{position_column} > #{position}"
|
|
310
|
+
).update_all(
|
|
311
|
+
"#{position_column} = (#{position_column} - 1)"
|
|
238
312
|
)
|
|
239
313
|
end
|
|
240
314
|
|
|
241
315
|
# This has the effect of moving all the higher items down one.
|
|
242
316
|
def increment_positions_on_higher_items
|
|
243
317
|
return unless in_list?
|
|
244
|
-
acts_as_list_class.
|
|
245
|
-
"#{
|
|
318
|
+
acts_as_list_class.unscoped.where(
|
|
319
|
+
"#{scope_condition} AND #{position_column} < #{send(position_column).to_i}"
|
|
320
|
+
).update_all(
|
|
321
|
+
"#{position_column} = (#{position_column} + 1)"
|
|
246
322
|
)
|
|
247
323
|
end
|
|
248
324
|
|
|
249
325
|
# This has the effect of moving all the lower items down one.
|
|
250
326
|
def increment_positions_on_lower_items(position)
|
|
251
|
-
acts_as_list_class.
|
|
252
|
-
"#{
|
|
253
|
-
|
|
327
|
+
acts_as_list_class.unscoped.where(
|
|
328
|
+
"#{scope_condition} AND #{position_column} >= #{position}"
|
|
329
|
+
).update_all(
|
|
330
|
+
"#{position_column} = (#{position_column} + 1)"
|
|
331
|
+
)
|
|
254
332
|
end
|
|
255
333
|
|
|
256
334
|
# Increments position (<tt>position_column</tt>) of all items in the list.
|
|
257
335
|
def increment_positions_on_all_items
|
|
258
|
-
acts_as_list_class.
|
|
259
|
-
"#{
|
|
336
|
+
acts_as_list_class.unscoped.where(
|
|
337
|
+
"#{scope_condition}"
|
|
338
|
+
).update_all(
|
|
339
|
+
"#{position_column} = (#{position_column} + 1)"
|
|
260
340
|
)
|
|
261
341
|
end
|
|
262
342
|
|
|
343
|
+
# Reorders intermediate items to support moving an item from old_position to new_position.
|
|
344
|
+
def shuffle_positions_on_intermediate_items(old_position, new_position, avoid_id = nil)
|
|
345
|
+
return if old_position == new_position
|
|
346
|
+
avoid_id_condition = avoid_id ? " AND #{self.class.primary_key} != #{avoid_id}" : ''
|
|
347
|
+
if old_position < new_position
|
|
348
|
+
# Decrement position of intermediate items
|
|
349
|
+
#
|
|
350
|
+
# e.g., if moving an item from 2 to 5,
|
|
351
|
+
# move [3, 4, 5] to [2, 3, 4]
|
|
352
|
+
acts_as_list_class.unscoped.where(
|
|
353
|
+
"#{scope_condition} AND #{position_column} > #{old_position} AND #{position_column} <= #{new_position}#{avoid_id_condition}"
|
|
354
|
+
).update_all(
|
|
355
|
+
"#{position_column} = (#{position_column} - 1)"
|
|
356
|
+
)
|
|
357
|
+
else
|
|
358
|
+
# Increment position of intermediate items
|
|
359
|
+
#
|
|
360
|
+
# e.g., if moving an item from 5 to 2,
|
|
361
|
+
# move [2, 3, 4] to [3, 4, 5]
|
|
362
|
+
acts_as_list_class.unscoped.where(
|
|
363
|
+
"#{scope_condition} AND #{position_column} >= #{new_position} AND #{position_column} < #{old_position}#{avoid_id_condition}"
|
|
364
|
+
).update_all(
|
|
365
|
+
"#{position_column} = (#{position_column} + 1)"
|
|
366
|
+
)
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
263
370
|
def insert_at_position(position)
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
371
|
+
if in_list?
|
|
372
|
+
old_position = send(position_column).to_i
|
|
373
|
+
return if position == old_position
|
|
374
|
+
shuffle_positions_on_intermediate_items(old_position, position)
|
|
375
|
+
else
|
|
376
|
+
increment_positions_on_lower_items(position)
|
|
377
|
+
end
|
|
378
|
+
set_list_position(position)
|
|
267
379
|
end
|
|
268
|
-
|
|
380
|
+
|
|
381
|
+
# used by insert_at_position instead of remove_from_list, as postgresql raises error if position_column has non-null constraint
|
|
382
|
+
def store_at_0
|
|
383
|
+
if in_list?
|
|
384
|
+
old_position = send(position_column).to_i
|
|
385
|
+
set_list_position(0)
|
|
386
|
+
decrement_positions_on_lower_items(old_position)
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
def update_positions
|
|
391
|
+
old_position = send("#{position_column}_was").to_i
|
|
392
|
+
new_position = send(position_column).to_i
|
|
393
|
+
return unless acts_as_list_class.unscoped.where("#{scope_condition} AND #{position_column} = #{new_position}").count > 1
|
|
394
|
+
shuffle_positions_on_intermediate_items old_position, new_position, id
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def check_scope
|
|
398
|
+
if changes.include?("#{scope_name}")
|
|
399
|
+
old_scope_id = changes["#{scope_name}"].first
|
|
400
|
+
new_scope_id = changes["#{scope_name}"].last
|
|
401
|
+
self["#{scope_name}"] = old_scope_id
|
|
402
|
+
send("decrement_positions_on_lower_items")
|
|
403
|
+
self["#{scope_name}"] = new_scope_id
|
|
404
|
+
send("add_to_list_#{add_new_at}")
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def reload_position
|
|
409
|
+
self.reload
|
|
410
|
+
end
|
|
411
|
+
end
|
|
269
412
|
end
|
|
270
413
|
end
|
|
271
414
|
end
|
data/lib/acts_as_list/version.rb
CHANGED
data/lib/acts_as_list.rb
CHANGED
|
@@ -1,2 +1,24 @@
|
|
|
1
1
|
require 'acts_as_list/active_record/acts/list'
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
module ActsAsList
|
|
4
|
+
if defined? Rails::Railtie
|
|
5
|
+
require 'rails'
|
|
6
|
+
class Railtie < Rails::Railtie
|
|
7
|
+
initializer 'acts_as_list.insert_into_active_record' do
|
|
8
|
+
ActiveSupport.on_load :active_record do
|
|
9
|
+
ActsAsList::Railtie.insert
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Railtie
|
|
16
|
+
def self.insert
|
|
17
|
+
if defined?(ActiveRecord)
|
|
18
|
+
ActiveRecord::Base.send(:include, ActiveRecord::Acts::List)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
ActsAsList::Railtie.insert
|
data/test/helper.rb
CHANGED
data/test/shared.rb
ADDED