鉴于我有以下型号:
class Location < Active::Record
has_many :storables, foreign_key: :bin_id
# ...
end
class Storable < Active::Record
belongs_to :bin, class_name: :Location, counter_cache: true
# ...
end
当我运行以下规范时,counter_cache
无法正确增加。方法#1
和#2
按预期工作,但不是#3
。是什么给了什么?
describe "location storables" do
specify "adding a storable increments the counter cache" do
l = Location.create
l.storables_count.should == 0 #=> PASSES
# method 1
s = Storable.create(bin: l)
l.reload
l.storables_count.should == 1 #=> PASSES
# method 2
l.storables.create
l.reload
l.storables_count.should == 2 #=> PASSES
# method 3
l.storables << Storable.create
l.reload
l.storables_count.should == 3 #=> FAILS, got 2 not 3
end
end
我对 counter_cache半工作感到困惑。我也无法发现配置问题。
在此项目中使用 Rails 3.2.12 。
更新
升级到 rails 4 没有帮助。此外,如果我将方法#3更改为以下内容,则测试通过:
# method 3
l.storables << Storable.create
puts "proxy : #{l.storables.count}" #=> 3
puts "relation : #{Storable.count}" #=> 3
puts "cache : #{l.storables_count}" #=> 2
Location.reset_counters(l.id, :storables) # corrects cache
l.reload
l.storables_count.should == 3 #=> PASSES
为什么不自动发生这种情况?
答案 0 :(得分:3)
首先,我不认为写l.storables << Storable.create
之类的东西是合适的。
通过写这个,发生了两件事:
Storable.create
使用location_id
nil创建一个新的可存储对象
l.storables <<
更新创建的对象,将location_id设置为l.id
,并以某种方式忘记更新计数器缓存。
这可能是ActiveRecord的错,因为它本来应该更聪明,但你实际上只是为了插入一个新的可存储记录而执行了两个SQL(插入可存储和更新可存储的set location_id = something)。无论如何,这是一个坏主意,如果你对location_id有一个外键约束,第一个插入甚至会失败。
所以请改用l.storables << Storable.new
PS:使用l.storables << Storable.create
,因为Storable.create
的返回值不是新记录,l
决定做什么有点困难。在某些情况下,它需要递增自己的计数器缓存,在其他情况下,它需要递增自己的计数器缓存并减少其他人的计数器缓存,否则它可能不需要做任何事情。