acts_as_ordered_tree 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -306,6 +306,9 @@ module ActsAsOrderedTree
306
306
  # nothing changed - quit
307
307
  return if parent_id == parent_id_was && position == position_was
308
308
 
309
+ self.class.find(self, :lock => true)
310
+ self[position_column], self[parent_column] = position, parent_id
311
+
309
312
  move_kind = case
310
313
  when id_was && parent_id != parent_id_was then :move
311
314
  when id_was && position != position_was then :reorder
@@ -363,7 +366,7 @@ module ActsAsOrderedTree
363
366
  "THEN :depth " +
364
367
  "ELSE #{depth_column} " +
365
368
  "END" if depth_column)
366
- ].compact.join(', ')
369
+ ]
367
370
 
368
371
  conditions = arel[pk].eq(id).or(
369
372
  arel[parent_column].eq(parent_id_was)
@@ -371,47 +374,61 @@ module ActsAsOrderedTree
371
374
  arel[parent_column].eq(parent_id)
372
375
  )
373
376
 
374
- binds = {:id => id,
375
- :parent_id_was => parent_id_was,
377
+ binds = {:parent_id_was => parent_id_was,
376
378
  :parent_id => parent_id,
377
379
  :position_was => position_was,
378
380
  :position => position,
379
381
  :depth => depth}
380
382
 
381
- ordered_tree_scope.where(conditions).update_all([assignments, binds])
383
+ update_changed_attributes! conditions, assignments, binds
382
384
  end
383
385
 
384
386
  # Internal
385
387
  def reorder!(parent_id, position_was, position)
386
- assignments = if position_was
387
- <<-SQL
388
- #{position_column} = CASE
389
- WHEN #{position_column} = :position_was
390
- THEN :position
391
- WHEN #{position_column} <= :position AND #{position_column} > :position_was AND :position > :position_was
392
- THEN #{position_column} - 1
393
- WHEN #{position_column} >= :position AND #{position_column} < :position_was AND :position < :position_was
394
- THEN #{position_column} + 1
395
- ELSE #{position_column}
396
- END
397
- SQL
398
- else
399
- <<-SQL
400
- #{position_column} = CASE
401
- WHEN #{position_column} > :position
402
- THEN #{position_column} + 1
403
- WHEN #{position_column} IS NULL
404
- THEN :position
405
- ELSE #{position_column}
406
- END
407
- SQL
408
- end
388
+ assignments = [
389
+ if position_was
390
+ <<-SQL
391
+ #{position_column} = CASE
392
+ WHEN #{position_column} = :position_was
393
+ THEN :position
394
+ WHEN #{position_column} <= :position AND #{position_column} > :position_was AND :position > :position_was
395
+ THEN #{position_column} - 1
396
+ WHEN #{position_column} >= :position AND #{position_column} < :position_was AND :position < :position_was
397
+ THEN #{position_column} + 1
398
+ ELSE #{position_column}
399
+ END
400
+ SQL
401
+ else
402
+ <<-SQL
403
+ #{position_column} = CASE
404
+ WHEN #{position_column} > :position
405
+ THEN #{position_column} + 1
406
+ WHEN #{position_column} IS NULL
407
+ THEN :position
408
+ ELSE #{position_column}
409
+ END
410
+ SQL
411
+ end
412
+ ]
409
413
 
410
414
  conditions = arel[parent_column].eq(parent_id)
411
-
412
415
  binds = {:position_was => position_was, :position => position}
413
416
 
414
- ordered_tree_scope.where(conditions).update_all([assignments, binds])
417
+ update_changed_attributes! conditions, assignments, binds
418
+ end
419
+
420
+ def update_changed_attributes!(scope_conditions, assignments, binds)
421
+ # add assignments for externally changed attributes
422
+ internal_attributes = [parent_column.to_s, position_column.to_s, depth_column.to_s, self.class.primary_key]
423
+ external_changed_attrs = changed - internal_attributes
424
+ unless external_changed_attrs.empty?
425
+ external_changed_attrs.each do |attr|
426
+ assignments << "#{attr} = CASE WHEN #{self.class.primary_key} = :id THEN :#{attr} ELSE #{attr} END"
427
+ binds[attr.to_sym] = self[attr]
428
+ end
429
+ end
430
+
431
+ ordered_tree_scope.where(scope_conditions).update_all([assignments.compact.join(', '), {:id => id}.merge(binds)])
415
432
  end
416
433
 
417
434
  # recursively load descendants
@@ -448,7 +465,7 @@ module ActsAsOrderedTree
448
465
 
449
466
  # Used in built-in around_move routine
450
467
  def update_counter_cache #:nodoc:
451
- parent_id_was = self[parent_column]
468
+ parent_id_was = send "#{parent_column}_was"
452
469
 
453
470
  yield
454
471
 
@@ -1,3 +1,3 @@
1
1
  module ActsAsOrderedTree
2
- VERSION = "1.1.1"
2
+ VERSION = "1.1.2"
3
3
  end
@@ -729,6 +729,32 @@ describe ActsAsOrderedTree, :transactional do
729
729
  child_3.move_to_child_of child_1
730
730
  record.reload.depth.should eq 3
731
731
  end
732
+
733
+ context "DefaultWithCallbacks" do
734
+ let!(:cb_root_1) { create :default_with_callbacks, :name => 'root_1' }
735
+ let!(:cb_root_2) { create :default_with_callbacks, :name => 'root_2' }
736
+ let!(:cb_child_1) { create :default_with_callbacks, :name => 'child_1', :parent => cb_root_1 }
737
+ let!(:cb_child_2) { create :default_with_callbacks, :name => 'child_2', :parent => cb_root_1 }
738
+
739
+ specify "new parent_id should be available in before_move" do
740
+ cb_root_2.stub(:before_move) { cb_root_2.parent_id.should eq cb_root_1.id }
741
+ cb_root_2.move_to_left_of cb_child_1
742
+ end
743
+
744
+ specify "new position should be available in before_reorder" do
745
+ cb_child_2.stub(:before_reorder) { cb_child_2.position.should eq 1 }
746
+ cb_child_2.move_to_left_of cb_child_1
747
+ end
748
+ end
749
+
750
+ end
751
+
752
+ context "changed attributes" do
753
+ specify "changed attributes should be saved" do
754
+ child_2.name = 'name100'
755
+ child_2.move_to_left_of child_1
756
+ child_2.reload.name.should eq 'name100'
757
+ end
732
758
  end
733
759
 
734
760
  end
@@ -7,14 +7,11 @@ if ActiveRecord::VERSION::STRING >= "3.1" && ENV['DB'] != 'sqlite3'
7
7
  module Concurrency
8
8
  # run block in its own thread, create +size+ threads
9
9
  def pool(size)
10
- body = proc do |x|
11
- ActiveRecord::Base.connection_pool.with_connection do
12
- yield x
10
+ size.times.map { |x|
11
+ Thread.new do
12
+ ActiveRecord::Base.connection_pool.with_connection { yield x }
13
13
  end
14
- end
15
- threads = size.times.map { |x| Thread.new { body.call(x) } }
16
-
17
- threads.each(&:join)
14
+ }.each(&:join)
18
15
  end
19
16
  end
20
17
  include Concurrency
data/spec/spec_helper.rb CHANGED
@@ -50,6 +50,7 @@ RSpec.configure do |config|
50
50
  ensure
51
51
  Default.delete_all
52
52
  DefaultWithCounterCache.delete_all
53
+ DefaultWithCallbacks.delete_all
53
54
  Scoped.delete_all
54
55
  end
55
56
  end
@@ -7,6 +7,10 @@ FactoryGirl.define do
7
7
  sequence(:name) { |n| "category #{n}" }
8
8
  end
9
9
 
10
+ factory :default_with_callbacks do
11
+ sequence(:name) { |n| "category #{n}" }
12
+ end
13
+
10
14
  factory :scoped do
11
15
  sequence(:scope_type) { |n| "type_#{n}" }
12
16
  sequence(:name) { |n| "category #{n}" }
@@ -16,6 +16,22 @@ class DefaultWithCounterCache < ActiveRecord::Base
16
16
  acts_as_ordered_tree :counter_cache => :categories_count
17
17
  end
18
18
 
19
+ class DefaultWithCallbacks < ActiveRecord::Base
20
+ self.table_name = "categories"
21
+
22
+ acts_as_ordered_tree
23
+
24
+ after_move :after_move
25
+ before_move :before_move
26
+ after_reorder :after_reorder
27
+ before_reorder :before_reorder
28
+
29
+ def after_move; end
30
+ def before_move; end
31
+ def after_reorder; end
32
+ def before_reorder; end
33
+ end
34
+
19
35
  class Scoped < ActiveRecord::Base
20
36
  self.table_name = "scoped"
21
37
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_ordered_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-09-14 00:00:00.000000000 Z
13
+ date: 2012-10-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -164,7 +164,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
164
164
  version: '0'
165
165
  segments:
166
166
  - 0
167
- hash: 2475944794341416152
167
+ hash: 1615306957006760355
168
168
  required_rubygems_version: !ruby/object:Gem::Requirement
169
169
  none: false
170
170
  requirements:
@@ -173,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
173
  version: '0'
174
174
  segments:
175
175
  - 0
176
- hash: 2475944794341416152
176
+ hash: 1615306957006760355
177
177
  requirements: []
178
178
  rubyforge_project: acts_as_ordered_tree
179
179
  rubygems_version: 1.8.24