acts_as_restful_list 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +9 -0
- data/README.rdoc +37 -2
- data/Todo.rdoc +6 -0
- data/VERSION +1 -1
- data/lib/acts_as_restful_list.rb +15 -4
- data/spec/acts_as_restful_list_spec.rb +115 -0
- metadata +4 -2
data/History.rdoc
ADDED
data/README.rdoc
CHANGED
@@ -1,12 +1,47 @@
|
|
1
1
|
= acts_as_restful_list
|
2
2
|
|
3
|
-
|
3
|
+
It's just like acts_as_list, but instead of having to clutter your code with
|
4
|
+
non-standard method calls like insert_at, acts_as_restful_list makes managing lists
|
5
|
+
simple. You update the position attribute just like you would update anything else
|
6
|
+
and the rest is taken care of for you.
|
7
|
+
|
8
|
+
For example:
|
9
|
+
|
10
|
+
class Item < ActiveRecord::Base
|
11
|
+
belongs_to :parent
|
12
|
+
acts_as_restful_list :scope => :parent
|
13
|
+
end
|
14
|
+
|
15
|
+
Now, simply CRUD away:
|
16
|
+
|
17
|
+
item = Item.create
|
18
|
+
item.position # 1
|
19
|
+
|
20
|
+
item2 = Item.create
|
21
|
+
item.position # 2
|
22
|
+
|
23
|
+
item3 = Item.create
|
24
|
+
item.position # 3
|
25
|
+
|
26
|
+
item.destroy
|
27
|
+
item2.position # 1
|
28
|
+
item3.position # 2
|
29
|
+
|
30
|
+
item3.position = 1
|
31
|
+
item3.save
|
32
|
+
item3.position # 1
|
33
|
+
item2.position # 2
|
34
|
+
|
35
|
+
different_parent = Item.create(:parent_id => 1)
|
36
|
+
different_parent.position # 1
|
37
|
+
|
38
|
+
And that's that.
|
4
39
|
|
5
40
|
== Note on Patches/Pull Requests
|
6
41
|
|
7
42
|
* Fork the project.
|
8
43
|
* Make your feature addition or bug fix.
|
9
|
-
* Add
|
44
|
+
* Add specs for it. This is important so I don't break it in a
|
10
45
|
future version unintentionally.
|
11
46
|
* Commit, do not mess with rakefile, version, or history.
|
12
47
|
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
data/Todo.rdoc
ADDED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/lib/acts_as_restful_list.rb
CHANGED
@@ -9,6 +9,7 @@ module ActsAsRestfulList
|
|
9
9
|
# +acts_as_restful_list+ makes the class it is called on automatically behave like an
|
10
10
|
# ordered list. There are a number of options you can set:
|
11
11
|
# * +column+: The column to use as the position column. It's set to position by default.
|
12
|
+
# * +scope+: The column to scope the list to. It takes a symbol with our without the _id.
|
12
13
|
def acts_as_restful_list(options = {})
|
13
14
|
include InstanceMethods
|
14
15
|
|
@@ -21,27 +22,37 @@ module ActsAsRestfulList
|
|
21
22
|
define_method 'position_column' do
|
22
23
|
configuration[:column].to_s
|
23
24
|
end
|
25
|
+
|
26
|
+
define_method 'scope_condition' do
|
27
|
+
if configuration[:scope].nil?
|
28
|
+
nil
|
29
|
+
else
|
30
|
+
column = configuration[:scope].to_s.match(/_id$/) ? configuration[:scope].to_s : "#{configuration[:scope]}_id"
|
31
|
+
value = self.send(column)
|
32
|
+
value.nil? ? "#{column} IS NULL" : "#{column} = #{value}"
|
33
|
+
end
|
34
|
+
end
|
24
35
|
end
|
25
36
|
end
|
26
37
|
|
27
38
|
module InstanceMethods
|
28
39
|
def set_position
|
29
|
-
last_record = self.class.last( :order => "#{position_column} ASC" )
|
40
|
+
last_record = self.class.last( :conditions => scope_condition, :order => "#{position_column} ASC" )
|
30
41
|
self.send( "#{position_column}=", ( last_record.nil? ? 1 : last_record.send(position_column) + 1 ) )
|
31
42
|
end
|
32
43
|
|
33
44
|
def reset_order_after_update
|
34
45
|
if self.send( "#{position_column}_changed?" )
|
35
46
|
if self.send( "#{position_column}_was" ) > self.send( position_column )
|
36
|
-
self.class.update_all("#{position_column} = (#{position_column} + 1)", "#{position_column} >= #{self.send( position_column )}
|
47
|
+
self.class.update_all("#{position_column} = (#{position_column} + 1)", [scope_condition, "#{position_column} >= #{self.send( position_column )}", "id != #{id}"].compact.join(' AND '))
|
37
48
|
else
|
38
|
-
self.class.update_all("#{position_column} = (#{position_column} - 1)", "#{position_column} <= #{self.send( position_column )}
|
49
|
+
self.class.update_all("#{position_column} = (#{position_column} - 1)", [scope_condition, "#{position_column} <= #{self.send( position_column )}", "#{position_column} >= #{self.send( "#{position_column}_was" )}", "id != #{id}"].compact.join(' AND '))
|
39
50
|
end
|
40
51
|
end
|
41
52
|
end
|
42
53
|
|
43
54
|
def reset_order_after_destroy
|
44
|
-
self.class.update_all("#{position_column} = (#{position_column} - 1)", "#{position_column} > #{self.send( position_column )}")
|
55
|
+
self.class.update_all("#{position_column} = (#{position_column} - 1)", [scope_condition, "#{position_column} > #{self.send( position_column )}"].compact.join(' AND '))
|
45
56
|
end
|
46
57
|
end
|
47
58
|
end
|
@@ -92,6 +92,10 @@ describe "ActsAsRestfulList" do
|
|
92
92
|
Mixin.all(:order => 'position ASC').collect(&:position).should == [1,2,3]
|
93
93
|
end
|
94
94
|
end
|
95
|
+
|
96
|
+
it 'should return nil for scope_condition since it was not set' do
|
97
|
+
Mixin.new.scope_condition.should be_nil
|
98
|
+
end
|
95
99
|
end
|
96
100
|
|
97
101
|
|
@@ -182,4 +186,115 @@ describe "ActsAsRestfulList" do
|
|
182
186
|
end
|
183
187
|
end
|
184
188
|
end
|
189
|
+
|
190
|
+
describe 'declaring acts_as_restful_list and setting the scope' do
|
191
|
+
before(:all) do
|
192
|
+
ActiveRecord::Schema.define(:version => 1) do
|
193
|
+
create_table :mixins do |t|
|
194
|
+
t.column :position, :integer
|
195
|
+
t.column :parent_id, :integer
|
196
|
+
t.column :created_at, :datetime
|
197
|
+
t.column :updated_at, :datetime
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
class Mixin < ActiveRecord::Base
|
202
|
+
acts_as_restful_list :scope => :parent_id
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
after(:all) do
|
207
|
+
Object.send(:remove_const, :Mixin)
|
208
|
+
|
209
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
210
|
+
ActiveRecord::Base.connection.drop_table(table)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'should define scope_condition as an instance method' do
|
215
|
+
Mixin.new.should respond_to(:scope_condition)
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'should return a scope condition that limits based on the parent_id' do
|
219
|
+
Mixin.new(:parent_id => 3).scope_condition.should == "parent_id = 3"
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'should return a scope limiting based parent_id being NULL if parent_id is nil' do
|
223
|
+
Mixin.new.scope_condition.should == "parent_id IS NULL"
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'should set the position based on the scope list when adding a new item' do
|
227
|
+
Mixin.create!.position.should == 1
|
228
|
+
Mixin.create!(:parent_id => 1).position.should == 1
|
229
|
+
Mixin.create!(:parent_id => 1).position.should == 2
|
230
|
+
Mixin.create!(:parent_id => 2).position.should == 1
|
231
|
+
end
|
232
|
+
|
233
|
+
describe 'reordering on update' do
|
234
|
+
before(:each) do
|
235
|
+
(1..4).each{ Mixin.create!(:parent_id => 1) }
|
236
|
+
(1..6).each{ Mixin.create!(:parent_id => 2) }
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'should automatically reorder the list if a record is updated with a lower position' do
|
240
|
+
fourth_mixin = Mixin.first( :conditions => { :position => 4, :parent_id => 1 } )
|
241
|
+
fourth_mixin.position = 2
|
242
|
+
fourth_mixin.save!
|
243
|
+
fourth_mixin.reload.position.should == 2
|
244
|
+
Mixin.all(:conditions => { :parent_id => 1 }, :order => 'position ASC').collect(&:position).should == [1,2,3,4]
|
245
|
+
Mixin.all(:conditions => { :parent_id => 2 }, :order => 'position ASC').collect(&:position).should == [1,2,3,4,5,6]
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'should automatically reorder the list if a record is updated with a higher position' do
|
249
|
+
second_mixin = Mixin.first( :conditions => { :position => 2, :parent_id => 1 } )
|
250
|
+
second_mixin.position = 4
|
251
|
+
second_mixin.save!
|
252
|
+
second_mixin.reload.position.should == 4
|
253
|
+
Mixin.all(:conditions => { :parent_id => 1 }, :order => 'position ASC').collect(&:position).should == [1,2,3,4]
|
254
|
+
Mixin.all(:conditions => { :parent_id => 2 }, :order => 'position ASC').collect(&:position).should == [1,2,3,4,5,6]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'should automatically reorder the list scoped by parent if the record id deleted' do
|
259
|
+
(1..4).each{ Mixin.create!(:parent_id => 1) }
|
260
|
+
(1..6).each{ Mixin.create!(:parent_id => 2) }
|
261
|
+
second_mixin = Mixin.first( :conditions => { :position => 2, :parent_id => 1 } )
|
262
|
+
second_mixin.destroy
|
263
|
+
Mixin.all(:conditions => { :parent_id => 1 }, :order => 'position ASC').collect(&:position).should == [1,2,3]
|
264
|
+
Mixin.all(:conditions => { :parent_id => 2 }, :order => 'position ASC').collect(&:position).should == [1,2,3,4,5,6]
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
describe 'declaring acts_as_restful_list and setting the scope without the _id' do
|
269
|
+
before(:all) do
|
270
|
+
ActiveRecord::Schema.define(:version => 1) do
|
271
|
+
create_table :mixins do |t|
|
272
|
+
t.column :position, :integer
|
273
|
+
t.column :parent_id, :integer
|
274
|
+
t.column :created_at, :datetime
|
275
|
+
t.column :updated_at, :datetime
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
class Mixin < ActiveRecord::Base
|
280
|
+
acts_as_restful_list :scope => :parent
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
after(:all) do
|
285
|
+
Object.send(:remove_const, :Mixin)
|
286
|
+
|
287
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
288
|
+
ActiveRecord::Base.connection.drop_table(table)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'should define scope_condition as an instance method' do
|
293
|
+
Mixin.new.should respond_to(:scope_condition)
|
294
|
+
end
|
295
|
+
|
296
|
+
it 'should return a scope condition that limits based on the parent_id' do
|
297
|
+
Mixin.new(:parent_id => 3).scope_condition.should == "parent_id = 3"
|
298
|
+
end
|
299
|
+
end
|
185
300
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_restful_list
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "'Trey Bean'"
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-17 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -34,9 +34,11 @@ extra_rdoc_files:
|
|
34
34
|
files:
|
35
35
|
- .document
|
36
36
|
- .gitignore
|
37
|
+
- History.rdoc
|
37
38
|
- LICENSE
|
38
39
|
- README.rdoc
|
39
40
|
- Rakefile
|
41
|
+
- Todo.rdoc
|
40
42
|
- VERSION
|
41
43
|
- lib/acts_as_restful_list.rb
|
42
44
|
- spec/acts_as_restful_list_spec.rb
|