首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在运行时禁用Rails关联counter_cache

如何在运行时禁用Rails关联counter_cache
EN

Stack Overflow用户
提问于 2012-02-17 01:43:26
回答 1查看 1.9K关注 0票数 6

我正在批量导入记录,不想每次都更新计数器。我希望在批量更新期间跳过counter_cache sql更新,然后在循环结束时调用reset_counters

我试过了:

代码语言:javascript
复制
my_model = MyModel.find_or_initialize_by_slug row[:slug]
my_model.association(:my_association).reflection.options[:counter_cache] = false
my_model.attributes = {:name => "Christopher"}
my_model.save!

但我可以在sql输出中看到它仍在更新counter_cache。

注意:我不能使用activerecord-import,因为我想执行upsert,而我使用的是postgresql

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-12-02 01:40:42

您有几个不同的选项来跳过计数器缓存的更新,您选择的选项实际上取决于您希望如何构建您的应用程序。我将讨论绕过计数器缓存的不同方法,并提到在执行此操作时可能需要考虑的一些事项。

基本上,有三种不同的方法可以跳过计数器缓存的更新:

  1. Monkey patch your model to disable the counter cache callback
  2. Use an update method that doesn't trigger callbacks
  3. Define指向不具有相同回调行为的同一个表的替代模型,并在批量插入到数据库

时使用该模型

请注意,上面的前两个选项通常与在ActiveRecord中禁用回调有关,这是有意义的,因为计数器缓存是通过回调在内部实现的。

当Rails加载一个与计数器缓存关联的模型时,它会动态定义回调方法。如果你想禁用它们作为回调,你必须首先弄清楚回调名称是什么。

为了实现这些回调,有两种主要的方法可以找出Rails定义的方法是什么。您可以读取Rails源代码,以找出它将通过字符串内插生成的名称,也可以使用内省来找出您的类响应哪些方法。我将给出一个示例,说明如何使用内省来查找由ActiveRecord定义的回调,以便自动实现计数器缓存。

假设您有一个名为SpecialReply的类,它继承自ActiveRecord::Base (this example comes from the test suite with Rails)的应答类。它具有一个计数器高速缓存列,定义如下:

代码语言:javascript
复制
class SpecialReply < ::Reply
  belongs_to :special_topic, :foreign_key => 'parent_id', :counter_cache => 'replies_count'
end

在控制台中,您可以使用.methods查看您的类所响应的方法。这会产生很多噪音,因为Object的每个实例已经响应了很多方法,所以您可以缩小列表范围,如下所示:

代码语言:javascript
复制
1.9.3-p194 :001 > sr = SpecialReply.new
1.9.3-p194 :002 > sr.methods - Object.methods

在第二行,显示我的SpecialReply实例响应的所有方法,减去所有对象响应的方法。这通常通过过滤掉不特定于您正在查看的类类型的方法来帮助进行内省。

不幸的是,即使在这种过滤之后,由于ActiveRecord添加到其所有后代类的方法,仍然存在大量噪声。在这种情况下,grep非常有用--因为ActiveRecord可以帮助创建包含字符串counter_cache (see the meta-programming used by ActiveRecord to generate a counter cache method for a belongs_to association)的计数器回调方法,所以您可以使用以下内容找到与计数器缓存相关的回调:

代码语言:javascript
复制
1.9.3-p194 :001 > sr = SpecialReply.new
1.9.3-p194 :002 > sr.methods.map(&:to_s).grep(/counter_cache/)

注意,由于grep操作一个字符串,而methods返回一个symbol方法名称数组,我们首先使用一个to_proc (&:)将所有符号转换为String,然后grep出包含counter_cache的符号。这给我留下了以下方法,它们可能是由ActiveRecord自动生成的,用于实现计数器缓存:

代码语言:javascript
复制
belongs_to_counter_cache_after_create_for_special_topic
belongs_to_counter_cache_before_destroy_for_special_topic
belongs_to_counter_cache_after_create_for_topic
belongs_to_counter_cache_before_destroy_for_topic
belongs_to_counter_cache_after_create_for_topic_with_primary_key
belongs_to_counter_cache_before_destroy_for_topic_with_primary_key

您应该能够在您的程序中遵循类似的过程来确定ActiveRecord添加的方法名称,以便您可以在existing instructions for removing callbacks之后删除它们。

从上述选项中进行选择实际上取决于程序的结构,以及您愿意为提高加载数据的效率而考虑的权衡。值得注意的是,前两个选项可以通过从外部修改类的行为(猴子修补)来降低代码的可读性,并且可以通过在更新数据时绕过业务规则(更新缓存列)来使系统不稳定。出于这些原因,我会考虑是否可以创建另一个类来以优化的方式加载数据,同时最小化对数据的可读性或一致性的影响。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9316283

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档