mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
0ed096ddf5
Also removes a false positive test that depends on the fixed bug: At this time, counter_cache does not work with polymorphic relationships (which is a bug). The test was added to make sure that no StaleObjectError is raised when the car is destroyed. No such error is currently raised because the lock version is not incremented by appending a wheel to the car. Furthermore, `assert_difference` succeeds because `car.wheels.count` does not check the counter cache, but the collection size. The test will fail if it is replaced with `car.wheels_count || 0`.
214 lines
6.6 KiB
Ruby
214 lines
6.6 KiB
Ruby
require 'cases/helper'
|
|
require 'models/topic'
|
|
require 'models/car'
|
|
require 'models/aircraft'
|
|
require 'models/wheel'
|
|
require 'models/engine'
|
|
require 'models/reply'
|
|
require 'models/category'
|
|
require 'models/categorization'
|
|
require 'models/dog'
|
|
require 'models/dog_lover'
|
|
require 'models/person'
|
|
require 'models/friendship'
|
|
require 'models/subscriber'
|
|
require 'models/subscription'
|
|
require 'models/book'
|
|
|
|
class CounterCacheTest < ActiveRecord::TestCase
|
|
fixtures :topics, :categories, :categorizations, :cars, :dogs, :dog_lovers, :people, :friendships, :subscribers, :subscriptions, :books
|
|
|
|
class ::SpecialTopic < ::Topic
|
|
has_many :special_replies, :foreign_key => 'parent_id'
|
|
has_many :lightweight_special_replies, -> { select('topics.id, topics.title') }, :foreign_key => 'parent_id', :class_name => 'SpecialReply'
|
|
end
|
|
|
|
class ::SpecialReply < ::Reply
|
|
belongs_to :special_topic, :foreign_key => 'parent_id', :counter_cache => 'replies_count'
|
|
end
|
|
|
|
setup do
|
|
@topic = Topic.find(1)
|
|
end
|
|
|
|
test "increment counter" do
|
|
assert_difference '@topic.reload.replies_count' do
|
|
Topic.increment_counter(:replies_count, @topic.id)
|
|
end
|
|
end
|
|
|
|
test "decrement counter" do
|
|
assert_difference '@topic.reload.replies_count', -1 do
|
|
Topic.decrement_counter(:replies_count, @topic.id)
|
|
end
|
|
end
|
|
|
|
test "reset counters" do
|
|
# throw the count off by 1
|
|
Topic.increment_counter(:replies_count, @topic.id)
|
|
|
|
# check that it gets reset
|
|
assert_difference '@topic.reload.replies_count', -1 do
|
|
Topic.reset_counters(@topic.id, :replies)
|
|
end
|
|
end
|
|
|
|
test "reset counters by counter name" do
|
|
# throw the count off by 1
|
|
Topic.increment_counter(:replies_count, @topic.id)
|
|
|
|
# check that it gets reset
|
|
assert_difference '@topic.reload.replies_count', -1 do
|
|
Topic.reset_counters(@topic.id, :replies_count)
|
|
end
|
|
end
|
|
|
|
test 'reset multiple counters' do
|
|
Topic.update_counters @topic.id, replies_count: 1, unique_replies_count: 1
|
|
assert_difference ['@topic.reload.replies_count', '@topic.reload.unique_replies_count'], -1 do
|
|
Topic.reset_counters(@topic.id, :replies, :unique_replies)
|
|
end
|
|
end
|
|
|
|
test "reset counters with string argument" do
|
|
Topic.increment_counter('replies_count', @topic.id)
|
|
|
|
assert_difference '@topic.reload.replies_count', -1 do
|
|
Topic.reset_counters(@topic.id, 'replies')
|
|
end
|
|
end
|
|
|
|
test "reset counters with modularized and camelized classnames" do
|
|
special = SpecialTopic.create!(:title => 'Special')
|
|
SpecialTopic.increment_counter(:replies_count, special.id)
|
|
|
|
assert_difference 'special.reload.replies_count', -1 do
|
|
SpecialTopic.reset_counters(special.id, :special_replies)
|
|
end
|
|
end
|
|
|
|
test "reset counter with belongs_to which has class_name" do
|
|
car = cars(:honda)
|
|
assert_nothing_raised do
|
|
Car.reset_counters(car.id, :engines)
|
|
end
|
|
assert_nothing_raised do
|
|
Car.reset_counters(car.id, :wheels)
|
|
end
|
|
end
|
|
|
|
test "reset the right counter if two have the same class_name" do
|
|
david = dog_lovers(:david)
|
|
|
|
DogLover.increment_counter(:bred_dogs_count, david.id)
|
|
DogLover.increment_counter(:trained_dogs_count, david.id)
|
|
|
|
assert_difference 'david.reload.bred_dogs_count', -1 do
|
|
DogLover.reset_counters(david.id, :bred_dogs)
|
|
end
|
|
assert_difference 'david.reload.trained_dogs_count', -1 do
|
|
DogLover.reset_counters(david.id, :trained_dogs)
|
|
end
|
|
end
|
|
|
|
test "update counter with initial null value" do
|
|
category = categories(:general)
|
|
assert_equal 2, category.categorizations.count
|
|
assert_nil category.categorizations_count
|
|
|
|
Category.update_counters(category.id, :categorizations_count => category.categorizations.count)
|
|
assert_equal 2, category.reload.categorizations_count
|
|
end
|
|
|
|
test "update counter for decrement" do
|
|
assert_difference '@topic.reload.replies_count', -3 do
|
|
Topic.update_counters(@topic.id, :replies_count => -3)
|
|
end
|
|
end
|
|
|
|
test "update counters of multiple records" do
|
|
t1, t2 = topics(:first, :second)
|
|
|
|
assert_difference ['t1.reload.replies_count', 't2.reload.replies_count'], 2 do
|
|
Topic.update_counters([t1.id, t2.id], :replies_count => 2)
|
|
end
|
|
end
|
|
|
|
test 'update multiple counters' do
|
|
assert_difference ['@topic.reload.replies_count', '@topic.reload.unique_replies_count'], 2 do
|
|
Topic.update_counters @topic.id, replies_count: 2, unique_replies_count: 2
|
|
end
|
|
end
|
|
|
|
test "update other counters on parent destroy" do
|
|
david, joanna = dog_lovers(:david, :joanna)
|
|
joanna = joanna # squelch a warning
|
|
|
|
assert_difference 'joanna.reload.dogs_count', -1 do
|
|
david.destroy
|
|
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, :friends_too)
|
|
end
|
|
end
|
|
|
|
test "reset counter of has_many :through association" do
|
|
subscriber = subscribers('second')
|
|
Subscriber.reset_counters(subscriber.id, 'books')
|
|
Subscriber.increment_counter('books_count', subscriber.id)
|
|
|
|
assert_difference 'subscriber.reload.books_count', -1 do
|
|
Subscriber.reset_counters(subscriber.id, 'books')
|
|
end
|
|
end
|
|
|
|
test "the passed symbol needs to be an association name or counter name" do
|
|
e = assert_raises(ArgumentError) do
|
|
Topic.reset_counters(@topic.id, :undefined_count)
|
|
end
|
|
assert_equal "'Topic' has no association called 'undefined_count'", e.message
|
|
end
|
|
|
|
test "reset counter works with select declared on association" do
|
|
special = SpecialTopic.create!(:title => 'Special')
|
|
SpecialTopic.increment_counter(:replies_count, special.id)
|
|
|
|
assert_difference 'special.reload.replies_count', -1 do
|
|
SpecialTopic.reset_counters(special.id, :lightweight_special_replies)
|
|
end
|
|
end
|
|
|
|
test "counters are updated both in memory and in the database on create" do
|
|
car = Car.new(engines_count: 0)
|
|
car.engines = [Engine.new, Engine.new]
|
|
car.save!
|
|
|
|
assert_equal 2, car.engines_count
|
|
assert_equal 2, car.reload.engines_count
|
|
end
|
|
|
|
test "counter caches are updated in memory when the default value is nil" do
|
|
car = Car.new(engines_count: nil)
|
|
car.engines = [Engine.new, Engine.new]
|
|
car.save!
|
|
|
|
assert_equal 2, car.engines_count
|
|
assert_equal 2, car.reload.engines_count
|
|
end
|
|
|
|
test "update counters in a polymorphic relationship" do
|
|
aircraft = Aircraft.create!
|
|
|
|
assert_difference 'aircraft.reload.wheels_count' do
|
|
aircraft.wheels << Wheel.create!
|
|
end
|
|
|
|
assert_difference 'aircraft.reload.wheels_count', -1 do
|
|
aircraft.wheels.first.destroy
|
|
end
|
|
end
|
|
end
|