我需要在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
被召唤并做其事。问题是,首先,即使您没有对记录进行任何更改,有没有办法强制回调被调用?
其次,计算平均值的方式是远更有效率,根本不让回调被调用,并一次性完成所有内容的平均值。这可能不会让回调被调用吗?
答案 0 :(得分:21)
我相信你所要求的是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).
请在set_callback
和skip_callback
的其他受支持的选项(例如条件和广告块)中引用已关联的ActiveSupport::Callbacks
。
答案 1 :(得分:12)
要禁用en-mass回调,请使用...
Survey.skip_callback(:save, :before, :calculate_averages)
然后启用它们......
Survey.set_callback(:save, :before, :calculate_average)
这会为所有实例跳过/设置。
答案 2 :(得分:6)
update_column
是一个ActiveRecord
函数,它不会运行任何回调,也不会运行验证。
答案 3 :(得分:3)
如果您想在检查每个调查后有条件地跳过回调,您可以编写自定义方法。
对于前。
`
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
`
它有点黑客但希望对你有用。
答案 4 :(得分:1)
希望这就是你要找的东西。
https://stackoverflow.com/a/6587546/2238259
对于您的第二个问题,我怀疑检查何时需要进行此计算会更好,最好是在网络流量处于低谷的指定时间批量处理。
编辑:Woops。我实际上找到了2个链接但显然失去了第一个链接。希望你能解决它。答案 5 :(得分:1)
对于Rails 3 ActiveSupport::Callbacks
为您提供必要的控制。您可以reset_callbacks
群集,或使用skip_callback
明智地禁用此类内容:
Vote.skip_callback(:save, :after, :add_points_to_user)
...之后您可以对:add_points_to_user
禁止的投票实例进行操作
答案 6 :(得分:1)
不适用于Rails 5
Survey.skip_callback(:save, :before, :calculate_average)
Works for Rails 5
Survey.skip_callback(:save, :before, :calculate_average, raise: false)
答案 7 :(得分:1)
Rails 5.2.3要求后方脚本不触发模型事件,update_column(column_name,value)达到了目的:
task.update_column(task_status, ReferenceDatum::KEY_COMPLETED)
https://apidock.com/rails/ActiveRecord/Persistence/update_column