Revision 565dc8e5
Added by Tomer Brisker over 8 years ago
app/models/concerns/counter_cache_fix.rb | ||
---|---|---|
extend ActiveSupport::Concern
|
||
|
||
included do
|
||
after_commit :update_counter_caches
|
||
after_commit :update_counter_caches, :on => :update
|
||
|
||
def update_counter_caches
|
||
self.changes.each do |key, (old_value, new_value)|
|
||
self.previous_changes.each do |key, (old_value, new_value)|
|
||
if key =~ /_id/
|
||
association = self.association(key.sub(/_id$/, '').to_sym)
|
||
if association.options[ :counter_cache ]
|
bundler.d/test.rb | ||
---|---|---|
gem 'rubocop-checkstyle_formatter', '~> 0.1'
|
||
gem "poltergeist"
|
||
gem 'test-unit' if RUBY_VERSION >= '2.2'
|
||
gem 'test_after_commit', '~> 0.4'
|
||
end
|
test/unit/concerns/counter_cache_test.rb | ||
---|---|---|
require 'test_helper'
|
||
|
||
# this test uses host and architecture to test that cached counters work as
|
||
# expected, this applies to all relations with counter_cache set.
|
||
class CounterCacheTest < ActiveSupport::TestCase
|
||
setup do
|
||
@host = FactoryGirl.create(:host)
|
||
@architecture = FactoryGirl.create(:architecture)
|
||
end
|
||
|
||
test 'hosts_count should be 0 for new architecture' do
|
||
assert_equal 0, @architecture.hosts_count
|
||
end
|
||
|
||
test 'assigning host to architecture updates count' do
|
||
assert_difference "@architecture.hosts_count" do
|
||
@architecture.hosts << @host
|
||
@architecture.save!
|
||
@architecture.reload
|
||
end
|
||
end
|
||
|
||
test 'assigning architecture to host updates count' do
|
||
assert_difference "@architecture.hosts_count" do
|
||
@host.architecture = @architecture
|
||
@host.save!
|
||
@architecture.reload
|
||
end
|
||
end
|
||
|
||
test 'removing architecture from host updates count' do
|
||
@host.architecture = @architecture
|
||
@host.save!
|
||
@architecture.reload
|
||
assert_equal 1, @architecture.hosts_count
|
||
assert_difference "@architecture.hosts_count", -1 do
|
||
@host.architecture = nil
|
||
@host.save!
|
||
@architecture.reload
|
||
end
|
||
end
|
||
|
||
test 'setting architecture_id on host updates count' do
|
||
assert_difference "@architecture.hosts_count" do
|
||
@host.update_attribute(:architecture_id, @architecture.id)
|
||
@architecture.reload
|
||
end
|
||
end
|
||
|
||
test 'moving host from one architecture to another should update both counters' do
|
||
@architecture2 = FactoryGirl.create(:architecture)
|
||
@host.architecture = @architecture
|
||
@host.save!
|
||
@architecture.reload
|
||
assert_equal 1, @architecture.hosts_count
|
||
assert_equal 0, @architecture2.hosts_count
|
||
@host.architecture = @architecture2
|
||
@host.save!
|
||
@architecture.reload
|
||
@architecture2.reload
|
||
assert_equal 0, @architecture.hosts_count
|
||
assert_equal 1, @architecture2.hosts_count
|
||
end
|
||
|
||
test 'moving host from one architecture to another by id should update both counters' do
|
||
@architecture2 = FactoryGirl.create(:architecture)
|
||
@host.architecture = @architecture
|
||
@host.save!
|
||
@architecture.reload
|
||
assert_equal 1, @architecture.hosts_count
|
||
assert_equal 0, @architecture2.hosts_count
|
||
@host.update_attribute(:architecture_id, @architecture2.id)
|
||
@architecture.reload
|
||
@architecture2.reload
|
||
assert_equal 0, @architecture.hosts_count
|
||
assert_equal 1, @architecture2.hosts_count
|
||
end
|
||
|
||
test 'destroying a host updates count' do
|
||
@host.architecture = @architecture
|
||
@host.save!
|
||
@architecture.reload
|
||
assert_difference "@architecture.hosts_count", -1 do
|
||
@host.destroy
|
||
@architecture.reload
|
||
end
|
||
end
|
||
end
|
Also available in: Unified diff
Fixes #12241 - Correct counter_cache deadlock fix
Previous fix had a bug - in `:after_commit` `self.changes` is empty, and the
changes are in `self.previous_changes`. Also this only needs to run on
update.
This commit adds tests to make sure cached_counters continue to work
correctly in the future.