如何在不运行Rails中的回调的情况下保存模型
我需要在Rails中保存模型时计算值。 所以我将calculate_averages
称为Survey
类的回调:
before_save :calculate_averages
但是,偶尔(最初我有10k记录需要此操作)我需要手动更新每条记录的所有平均值。 没问题,我有以下代码:
Survey.all.each do |survey| survey.some_average = (survey.some_value + survey.some_other_value) / 2.to_f #and some more averages... survey.save! end
在运行此代码之前,我担心calculate_averages
会被调用并复制它,甚至可能会导致我正在做事的方式出现问题。 好吧,那么我想,好吧,我什么都不做,让calculate_averages
被调用并做其事。 问题是,首先,即使您没有对记录进行任何更改,是否有办法强制回调被调用?
其次,计算平均值的方式更有效率,根本不让回调被调用,并一次性完成所有事件的平均值。 这可能不会让回调被调用吗?
我相信你所要求的是使用ActiveSupport::Callbacks
可以实现的。 看看set_callback
和skip_callback
。
为了“即使您没有对记录进行任何更改也强制调用回调”,您需要将回调注册到某些事件,例如save, validate etc.
。
set_callback :save, :before, :my_before_save_callback
要跳过before_save
回调,您可以:
Survey.skip_callback(:save, :before, :calculate_average).
请在其他支持的选项(如条件和块)上引用链接的ActiveSupport::Callbacks
到set_callback
和skip_callback
。
要禁用en-mass回调,请使用…
Survey.skip_callback(:calculate_averages)
然后启用它们……
Survey.set_callback(:calculate_average)
这会跳过/设置所有实例。
update_column
是一个ActiveRecord
函数,它不运行任何回调,也不运行validation。
如果您想在检查每个调查后有条件地跳过回调,则可以编写自定义方法。
对于前者
- 修改后的回调 –
`
before_save :calculate_averages, if: Proc.new{ |survey| !survey.skip_callback }
`
- 新实例方法 –
`
def skip_callback(value = false) @skip_callback = @skip_callback ? @skip_callback : value end
`
- 更新调查的脚本 –
`
Survey.all.each do |survey| survey.some_average = (survey.some_value + survey.some_other_value) / 2.to_f #and some more averages... survey.skip_callback(true) survey.save! end
`
它有点黑客但希望对你有用。
希望这是你正在寻找的。
https://stackoverflow.com/a/6587546/2238259
对于您的第二个问题,我怀疑检查何时需要进行此计算会更好,最好是在网络流量处于低谷的指定时间批量处理。
编辑:Woops。 我实际上找到了2个链接但显然失去了第一个链接。 希望你能解决这个问题。
对于Rails 3 ActiveSupport::Callbacks
为您提供必要的控制。 你可以reset_callbacks
,或者使用skip_callback
来明智地禁用这样:
Vote.skip_callback(:save, :after, :add_points_to_user)
…之后您可以使用以下命令对Vote实例进行操作:add_points_to_user
被禁止
不适用于Rails 5
Survey.skip_callback(:save, :before, :calculate_average)
适用于Rails 5
Survey.skip_callback(:save, :before, :calculate_average, raise: false)