我有一个使用rails'内置的counter_cache关联来增加/减少计数。我有一个要求,当我为特定情况销毁模型时,我需要禁用它。我试图做Model.skip_callback(:destroy, :belongs_to_counter_cache_after_update)
之类的事情,但它似乎没有按预期工作(即它仍然最终减少相关模型)。任何有用的指示将不胜感激。
答案 0 :(得分:0)
您可以创建一个标志来决定何时应该运行回调,例如:
class YourModel
attr_accessor :skip_counter_cache_update
def decrement_callback
return if @skip_counter_cache_update
# Run callback to decrement counter cache
...
end
end
因此,在销毁模型的对象之前,只需设置skip_counter_cache_update
的值:
@object = YourModel.find(some_id)
@object.skip_counter_cache_update = true
@object.destroy
所以它不会运行递减回调。
答案 1 :(得分:0)
一种选择是临时覆盖负责在销毁时更新缓存计数的方法。 例如,如果您有以下两个模型
class Category < ActiveRecord::Base
has_many :products
end
class Product < ActiveRecord::Base
belongs_to :category, counter_cache: true
end
现在,您可以尝试使用以下
查找负责更新缓存计数的方法2.1.5 :038 > Product.new.methods.map(&:to_s).grep(/counter_cache/)
这显示了与counter_cache相关的所有产品实例方法,结果如下
=> ["belongs_to_counter_cache_before_destroy_for_category", "belongs_to_counter_cache_after_create_for_category", "belongs_to_counter_cache_after_update_for_category"]
从显示的方法名称
"belongs_to_counter_cache_after_create_for_category"
可能负责销毁后的计数器缓存更新。 所以我决定暂时使用一个没有做任何事情的假方法覆盖这个方法(跳过计数器缓存更新)
Product.class_eval do
def fake_belongs_to_counter_cache_before_destroy_for_category; end
alias_method :real_belongs_to_counter_cache_before_destroy_for_category, :belongs_to_counter_cache_before_destroy_for_category
alias_method :belongs_to_counter_cache_before_destroy_for_category, :fake_belongs_to_counter_cache_before_destroy_for_category
end
现在,如果您要销毁任何产品对象,它将不会更新Category表中的计数器缓存。 但是,在运行代码以销毁特定对象后,恢复实际方法非常重要。要恢复到实际的类方法,您可以执行以下操作
Product.class_eval do
alias_method :belongs_to_counter_cache_before_destroy_for_category, :real_belongs_to_counter_cache_before_destroy_for_category
remove_method :real_belongs_to_counter_cache_before_destroy_for_category
remove_method :fake_belongs_to_counter_cache_before_destroy_for_category
end
为了确保在特定的销毁任务之后始终恢复方法定义,您可以编写一个类方法,确保同时运行覆盖和恢复代码
class Product < ActiveRecord::Base
belongs_to :category, counter_cache: true
def self.without_counter_cache_update_on_destroy(&block)
self.class_eval do
def fake_belongs_to_counter_cache_before_destroy_for_category; end
alias_method :real_belongs_to_counter_cache_before_destroy_for_category, :belongs_to_counter_cache_before_destroy_for_category
alias_method :belongs_to_counter_cache_before_destroy_for_category, :fake_belongs_to_counter_cache_before_destroy_for_category
end
yield
self.class_eval do
alias_method :belongs_to_counter_cache_before_destroy_for_category, :real_belongs_to_counter_cache_before_destroy_for_category
remove_method :real_belongs_to_counter_cache_before_destroy_for_category
remove_method :fake_belongs_to_counter_cache_before_destroy_for_category
end
end
end
现在,如果您销毁以下
中的任何产品对象Product.without_counter_cache_update_on_destroy { Product.last.destroy }
它不会更新Category表中的计数器缓存。
参考文献:
禁用ActiveModel回调https://jeffkreeftmeijer.com/2010/disabling-activemodel-callbacks/
临时覆盖方法:https://gist.github.com/aeden/1069124