acts_as_restful_list 0.0.3 → 0.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.
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