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 ADDED
@@ -0,0 +1,9 @@
1
+ === Version 0.1.0 / 2010-02-17
2
+
3
+ * enhancements
4
+ * added ability to scope the list.
5
+
6
+ === Version 0.0.3 / 2010-02-14
7
+
8
+ * enhancements
9
+ * can set the position column
data/README.rdoc CHANGED
@@ -1,12 +1,47 @@
1
1
  = acts_as_restful_list
2
2
 
3
- Description goes here.
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 tests for it. This is important so I don't break it in a
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
@@ -0,0 +1,6 @@
1
+ * enhancements
2
+ * Add ability to provide custom scope
3
+ * Add ability to scope on multiple columns
4
+
5
+ * Cleanup
6
+ * Reduce some of the duplication of examples in specs
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.1.0
@@ -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 )} AND id != #{id}")
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 )} AND #{position_column} >= #{self.send( "#{position_column}_was" )} AND id != #{id}")
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.3
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-14 00:00:00 -07:00
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