Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

reset_counters() was crashing when there were multiple belongs_to ass…

…ociations with the same foreign key.

This closes #5200.
  • Loading branch information...
commit ff0d9b93b9074c479dd6de657c71812f0ac40cbe 1 parent ce0dd56
@Pliny Pliny authored rafaelfranca committed
View
6 activerecord/CHANGELOG.md
@@ -1,5 +1,11 @@
## Rails 4.0.0 (unreleased) ##
+* Fix `reset_counters` when there are multiple `belongs_to` association with the
+ same foreign key and one of them have a counter cache.
+ Fixes #5200.
+
+ *Dave Desrochers*
+
* `serialized_attributes` and `_attr_readonly` become class method only. Instance reader methods are deprecated.
*kennyj*
View
2  activerecord/lib/active_record/counter_cache.rb
@@ -25,7 +25,7 @@ def reset_counters(id, *counters)
foreign_key = has_many_association.foreign_key.to_s
child_class = has_many_association.klass
belongs_to = child_class.reflect_on_all_associations(:belongs_to)
- reflection = belongs_to.find { |e| e.foreign_key.to_s == foreign_key }
+ reflection = belongs_to.find { |e| e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
counter_name = reflection.counter_cache_column
stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({
View
11 activerecord/test/cases/counter_cache_test.rb
@@ -8,9 +8,11 @@
require 'models/categorization'
require 'models/dog'
require 'models/dog_lover'
+require 'models/person'
+require 'models/friendship'
class CounterCacheTest < ActiveRecord::TestCase
- fixtures :topics, :categories, :categorizations, :cars, :dogs, :dog_lovers
+ fixtures :topics, :categories, :categorizations, :cars, :dogs, :dog_lovers, :people, :friendships
class ::SpecialTopic < ::Topic
has_many :special_replies, :foreign_key => 'parent_id'
@@ -109,4 +111,11 @@ class ::SpecialReply < ::Reply
Topic.update_counters([t1.id, t2.id], :replies_count => 2)
end
end
+
+ test "reset the right counter if two have the same foreign key" do
+ michael = people(:michael)
+ assert_nothing_raised(ActiveRecord::StatementInvalid) do
+ Person.reset_counters(michael.id, :followers)
+ end
+ end
end
View
4 activerecord/test/fixtures/friendships.yml
@@ -0,0 +1,4 @@
+Connection 1:
+ id: 1
+ person_id: 1
+ friend_id: 2
View
3  activerecord/test/fixtures/people.yml
@@ -4,15 +4,18 @@ michael:
primary_contact_id: 2
number1_fan_id: 3
gender: M
+ followers_count: 1
david:
id: 2
first_name: David
primary_contact_id: 3
number1_fan_id: 1
gender: M
+ followers_count: 1
susan:
id: 3
first_name: Susan
primary_contact_id: 2
number1_fan_id: 1
gender: F
+ followers_count: 1
View
4 activerecord/test/models/friendship.rb
@@ -0,0 +1,4 @@
+class Friendship < ActiveRecord::Base
+ belongs_to :friend, class_name: 'Person'
+ belongs_to :follower, foreign_key: 'friend_id', class_name: 'Person', counter_cache: :followers_count
+end
View
2  activerecord/test/models/person.rb
@@ -8,6 +8,8 @@ class Person < ActiveRecord::Base
has_many :posts_with_no_comments, -> { includes(:comments).where('comments.id is null').references(:comments) },
:through => :readers, :source => :post
+ has_many :followers, foreign_key: 'friend_id', class_name: 'Friendship'
+
has_many :references
has_many :bad_references
has_many :fixed_bad_references, -> { where :favourite => true }, :class_name => 'BadReference'
View
6 activerecord/test/schema/schema.rb
@@ -270,6 +270,11 @@ def create_table(*args, &block)
t.string :name
end
+ create_table :friendships, :force => true do |t|
+ t.integer :friend_id
+ t.integer :person_id
+ end
+
create_table :goofy_string_id, :force => true, :id => false do |t|
t.string :id, :null => false
t.string :info
@@ -476,6 +481,7 @@ def create_table(*args, &block)
t.references :number1_fan
t.integer :lock_version, :null => false, :default => 0
t.string :comments
+ t.integer :followers_count, :default => 0
t.references :best_friend
t.references :best_friend_of
t.timestamps
Please sign in to comment.
Something went wrong with that request. Please try again.