如何在不运行Rails中的回调的情况下保存模型

时间:2014-01-27 01:44:24

标签: ruby-on-rails ruby-on-rails-3 activerecord ruby-on-rails-3.2 rails-activerecord

我需要在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被召唤并做其事。问题是,首先,即使您没有对记录进行任何更改,有没有办法强制回调被调用?

其次,计算平均值的方式是更有效率,根本不让回调被调用,并一次性完成所有内容的平均值。这可能不会让回调被调用吗?

8 个答案:

答案 0 :(得分:21)

我相信你所要求的是ActiveSupport::Callbacks。请查看set_callbackskip_callback

为了“即使您没有对记录进行任何更改也强制调用回调”,您需要将回调注册到某个事件,例如save, validate etc.

set_callback :save, :before, :my_before_save_callback

要跳过before_save回调,您可以执行以下操作:

Survey.skip_callback(:save, :before, :calculate_average). 

请在set_callbackskip_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)

https://github.com/thoughtbot/factory_bot/issues/931

答案 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