Oli*_*ver 11 caching ruby-on-rails has-many-through
我有以下三种模型(大规模简化):
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
Run Code Online (Sandbox Code Playgroud)
似乎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>]
Run Code Online (Sandbox Code Playgroud)
这确实如你所料.a.cs很好地通过a.bs关系.
008 > a2 = A.create
009 > a2.cs
=> []
010 > a2.bs << b
011 > a2.cs
=> []
Run Code Online (Sandbox Code Playgroud)
所以第一次调用a2.cs(导致数据库查询)非常正确地返回没有Cs.然而,第二次调用表明Cs明显不足,即使它们应该很好(不会发生数据库查询).
012 > A.find(a2.id).cs
=> [#<C id: 1, b_id: 1>]
Run Code Online (Sandbox Code Playgroud)
同样,执行db查询以获取A记录和关联的C.
那么,回到问题:如何强制rails不使用缓存结果?我当然可以让自己做出这种解决方法(如控制台步骤12所示),但由于这只会导致额外的两个查询,所以我宁愿不这样做.
Dan*_*rip 16
我对这个问题做了一些更多的研究.尽管clear_association_cache使用方便,但在每次使缓存失效的操作之后添加它都不会感觉干燥.我认为Rails应该能够跟踪这一点.谢天谢地,有办法!
我将使用你的示例模型:A(有很多B,有很多C到B),B(属于A,有很多C)和C(属于B).
我们需要使用touch: true该belongs_to方法的选项.此方法更新updated_at父模型上的属性,但更重要的是它还会触发after_touch回调.只要修改,创建或销毁B或C的相关实例,此回调允许我们自动清除A的任何实例的关联缓存.
首先修改belongs_toB和C 的方法调用,添加touch:true
class B < ActiveRecord::Base
belongs_to :a, touch: true
has_many :cs
end
class C < ActiveRecord::Base
belongs_to :b, touch: true
end
Run Code Online (Sandbox Code Playgroud)
然后after_touch向A 添加回调
class A < ActiveRecord::Base
has_many :bs
has_many :cs, through: :bs
after_touch :clear_association_cache
end
Run Code Online (Sandbox Code Playgroud)
现在我们可以安全地破解,创建各种修改/创建/销毁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
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
7100 次 |
| 最近记录: |