我有以下三个模型(大规模简化):
class A < ActiveRecord::Base
has_many :bs
has_many :cs, :through => :bs
end
class B < ActiveRecord::Base
belongs_to :a
has_many :cs
end
class C < ActiveRecord::Base
belongs_to :b
end
看起来A.cs在第一次使用时(每个对象)就被缓存了,而我真的不希望它被缓存。
下面是一个控制台会话,它突出显示了这个问题(其中的不足之处已被编辑掉)
首先,它的工作方式
rails console
001 > b = B.create
002 > c = C.new
003 > c.b = b
004 > c.save
005 > a = A.create
006 > a.bs << b
007 > a.cs
=> [#<C id: 1, b_id: 1>]
这确实如您所料,a.cs在www.example.com关系中运行良好a.bs。
现在来说说缓存的愤怒
008 > a2 = A.create
009 > a2.cs
=> []
010 > a2.bs << b
011 > a2.cs
=> []
因此,第一次调用a2.cs(导致db查询)完全正确地没有返回Cs。然而,第二次调用显示明显缺少Cs,即使它们应该在那里(没有发生db查询)。
只是为了测试我的理智不是责备
012 > A.find(a2.id).cs
=> [#<C id: 1, b_id: 1>]
同样,执行db查询以获得A记录和相关联的C。
所以,回到问题:我如何强制rails不使用缓存的结果呢?我当然可以让自己做这个变通方案(如控制台步骤12所示),但因为这会导致在只需要一个查询时多出两个查询,所以我宁愿不这样做。
6条答案
按热度按时间eulz3vhy1#
我对这个问题做了更多的研究。虽然使用
clear_association_cache
足够方便,但在每次该高速缓存无效的操作之后添加它并不感到干燥。我认为Rails应该能够跟踪这一点。谢天谢地,有一种方法!我将使用您的示例模型:A(有许多B,有许多C到B),B(属于A,有许多C),C(属于B)。
我们需要为
belongs_to
方法使用touch: true
选项。该方法更新父模型上的updated_at
属性,但更重要的是,它还触发after_touch
回调。该回调允许我们在修改、创建或销毁B或C的相关示例时自动清除A的任何示例的关联缓存。首先修改B和C的
belongs_to
方法调用,添加touch:true
然后将
after_touch
回调添加到A现在我们可以安全地破解,创建各种修改/创建/销毁B和C示例的方法,它们所属的A示例将自动更新其缓存,而不必记住到处调用
clear_association_cache
。根据您使用模型B的方式,您可能还希望在那里添加
after_touch
回调。belongs_to
选项和ActiveRecord回调的文档:http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-belongs_to
希望这有帮助!
新的Rails版本
正如@stevenspiel评论的那样,这个方法是私有的,然后在较新的Rails中,它甚至被删除了。所以你可以使用
#reset
或#reload
示例(可能你想重置关联)。uyto3xhc2#
所有的关联方法都是围绕缓存构建的,缓存可以保持最近查询的结果可用于进一步的操作。该高速缓存甚至可以跨方法共享。例如:
但是,如果你想重新加载该高速缓存,因为数据可能已经被应用程序的其他部分更改了呢?只需将true传递给关联调用:
来源http://guides.rubyonrails.org/association_basics.html
z0qdvdin3#
(Edit:看丹尼尔Waltrip的回答,他的远远比我的好)
所以,在输入了所有这些内容并检查了一些无关的东西之后,我的眼睛碰巧看到了关联基础指南的“3.1控制缓存”部分。
我会做一个好孩子,分享答案,因为我刚刚花了大约八个小时的沮丧徒劳的谷歌搜索。
但是,如果你想重新加载该高速缓存,因为数据可能已经被应用程序的其他部分更改了呢?只需将true传递给关联调用:
所以这个故事的寓意是:RTFM;所有的。
编辑:所以必须把
true
放在所有的地方可能不是一件好事,该高速缓存会被绕过,即使它不需要。丹尼尔Waltrip在评论中提供的解决方案要好得多:使用clear_association_cache
所以现在,我们不仅要RTFM,我们还应该搜索
:nodoc:
s的代码!zzzyeukh4#
我发现了另一种禁用查询缓存的方法。
我在本地验证了它的工作。我通过查看 active_record/associations/association.rb 中的active_record源代码发现了这一点:
nzk0hqpo5#
要清除该高速缓存,请使用
.reload
来源:控制缓存
3df52oht6#
您可以使用
extend
选项并提供一个模块来在加载之前重置加载,如下所示: