3

鉴于我有以下模型:

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 half working感到困惑。我也无法发现配置问题。

在这个项目上使用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

为什么这不会自动发生?

4

1 回答 1

3

一方面,我认为写类似l.storables << Storable.create.

通过写这个,会发生两件事:

  1. Storable.createlocation_id用nil创建一个新的 Storable 对象

  2. l.storables <<更新创建的对象,将 location_id 设置为l.id,并且不知何故忘记更新计数器缓存。

这可能是 ActiveRecord 的错,因为它应该更聪明,但是您实际上已经执行了两个 SQL(插入可存储并更新可存储集 location_id = something)只是为了插入一个新的可存储记录。无论如何,这是一个坏主意,如果您对 location_id 有外键约束,那么第一次插入甚至会失败。

所以l.storables << Storable.new改用

PS:有了l.storables << Storable.create,由于 的返回值Storable.create不是新记录,所以有点难以l抉择。在某些情况下,它需要增加自己的计数器缓存,在其他情况下,它需要增加自己的计数器缓存并减少其他人的计数器缓存,或者它可能什么都不做。

于 2013-07-11T09:13:09.447 回答