Created
April 14, 2014 03:28
-
-
Save tenderlove/10613756 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb | |
index 8272a55..e8083a5 100644 | |
--- a/activerecord/lib/active_record/associations/belongs_to_association.rb | |
+++ b/activerecord/lib/active_record/associations/belongs_to_association.rb | |
@@ -46,8 +46,9 @@ module ActiveRecord | |
def update_counters(record) | |
with_cache_name do |name| | |
return unless different_target? record | |
- record.class.increment_counter(name, record.id) | |
- decrement_counter name | |
+ expected = record.read_attribute name | |
+ record.class.increment_counter(name, record.id, expected) | |
+ decrement_counter record, name | |
end | |
end | |
@@ -55,9 +56,10 @@ module ActiveRecord | |
with_cache_name { |name| decrement_counter name } | |
end | |
- def decrement_counter counter_cache_name | |
+ def decrement_counter record, counter_cache_name | |
if foreign_key_present? | |
- klass.decrement_counter(counter_cache_name, target_id) | |
+ expected = record.read_attribute counter_cache_name | |
+ klass.decrement_counter(counter_cache_name, target_id, expected) | |
end | |
end | |
diff --git a/activerecord/lib/active_record/associations/builder/belongs_to.rb b/activerecord/lib/active_record/associations/builder/belongs_to.rb | |
index 5ccaa55..68b7570 100644 | |
--- a/activerecord/lib/active_record/associations/builder/belongs_to.rb | |
+++ b/activerecord/lib/active_record/associations/builder/belongs_to.rb | |
@@ -32,7 +32,8 @@ module ActiveRecord::Associations::Builder | |
def belongs_to_counter_cache_after_create(reflection) | |
if record = send(reflection.name) | |
cache_column = reflection.counter_cache_column | |
- record.class.increment_counter(cache_column, record.id) | |
+ expected = record.read_attribute cache_column | |
+ record.class.increment_counter(cache_column, record.id, expected) | |
@_after_create_counter_called = true | |
end | |
end | |
@@ -43,7 +44,8 @@ module ActiveRecord::Associations::Builder | |
record = send reflection.name | |
if record && !self.destroyed? | |
cache_column = reflection.counter_cache_column | |
- record.class.decrement_counter(cache_column, record.id) | |
+ expected = record.read_attribute cache_column | |
+ record.class.decrement_counter(cache_column, record.id, expected) | |
end | |
end | |
end | |
diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb | |
index dcbdf75..5277a00 100644 | |
--- a/activerecord/lib/active_record/counter_cache.rb | |
+++ b/activerecord/lib/active_record/counter_cache.rb | |
@@ -70,14 +70,16 @@ module ActiveRecord | |
# # UPDATE posts | |
# # SET comment_count = COALESCE(comment_count, 0) + 1 | |
# # WHERE id IN (10, 15) | |
- def update_counters(id, counters) | |
+ def update_counters(id, expected, counters) | |
+ scope = unscoped | |
updates = counters.map do |counter_name, value| | |
operator = value < 0 ? '-' : '+' | |
quoted_column = connection.quote_column_name(counter_name) | |
+ scope = scope.where(counter_name => expected) | |
"#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}" | |
end | |
- unscoped.where(primary_key => id).update_all updates.join(', ') | |
+ scope.where(primary_key => id).update_all updates.join(', ') | |
end | |
# Increment a numeric field by one, via a direct SQL update. | |
@@ -96,8 +98,8 @@ module ActiveRecord | |
# | |
# # Increment the post_count column for the record with an id of 5 | |
# DiscussionBoard.increment_counter(:post_count, 5) | |
- def increment_counter(counter_name, id) | |
- update_counters(id, counter_name => 1) | |
+ def increment_counter(counter_name, id, expected) | |
+ update_counters(id, expected, counter_name => 1) | |
end | |
# Decrement a numeric field by one, via a direct SQL update. | |
@@ -114,8 +116,8 @@ module ActiveRecord | |
# | |
# # Decrement the post_count column for the record with an id of 5 | |
# DiscussionBoard.decrement_counter(:post_count, 5) | |
- def decrement_counter(counter_name, id) | |
- update_counters(id, counter_name => -1) | |
+ def decrement_counter(counter_name, id, expected) | |
+ update_counters(id, expected, counter_name => -1) | |
end | |
end | |
end | |
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb | |
index 4d63b04..a2d211f 100644 | |
--- a/activerecord/lib/active_record/locking/optimistic.rb | |
+++ b/activerecord/lib/active_record/locking/optimistic.rb | |
@@ -164,7 +164,7 @@ module ActiveRecord | |
# Make sure the lock version column gets updated when counters are | |
# updated. | |
- def update_counters(id, counters) | |
+ def update_counters(id, counters, expected) | |
counters = counters.merge(locking_column => 1) if locking_enabled? | |
super | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment