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

at.*_*at. 24 activerecord ruby-on-rails ruby-on-rails-3 ruby-on-rails-3.2 rails-activerecord

我需要在Rails中保存模型时计算值.所以我称之为calculate_averages一个Survey类的回调:

before_save :calculate_averages
Run Code Online (Sandbox Code Playgroud)

但是,偶尔(最初我有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
Run Code Online (Sandbox Code Playgroud)

在运行这段代码之前,我担心calculate_averages它会被调用并复制它,甚至可能会导致我正在做的事情出现问题.好吧,那么我想,好吧,我只是什么也不做,让我们calculate_averages打电话来做它的事.问题是,首先,即使您没有对记录进行任何更改,有没有办法强制回调被调用?

其次,平均的方式计算这是远远更有效率根本就没有让回调被调用的一切,做的一切平均值的一次.这可能不会让回调被调用吗?

vee*_*vee 23

我相信你所要求的是可以实现的ActiveSupport::Callbacks.看看set_callbackskip_callback.

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

set_callback :save, :before, :my_before_save_callback
Run Code Online (Sandbox Code Playgroud)

要跳过before_save回调,您可以:

Survey.skip_callback(:save, :before, :calculate_average). 
Run Code Online (Sandbox Code Playgroud)

请参考ActiveSupport::Callbacks其他支持的选项链接,例如条件和块set_callbackskip_callback.


raf*_*ch2 15

要禁用en-mass回调,请使用...

Survey.skip_callback(:save, :before, :calculate_averages)
Run Code Online (Sandbox Code Playgroud)

然后启用它们......

Survey.set_callback(:save, :before, :calculate_average)
Run Code Online (Sandbox Code Playgroud)

这会跳过/设置所有实例.

  • 这不是`skip_callback`命令的有效语法.第一个参数不是您定义的方法的名称,它是回调阶段之一,例如.`save`,`validate`,`commit`等.正确的语法是`Survey.skip_callback(:save,:before,:calculate_averages)`参见:http://api.rubyonrails.org/classes/的ActiveSupport /回调/ ClassMethods.html (13认同)
  • 这仅限于运行计算的Rails实例.任何其他地方发生的事情都不会受到影响. (4认同)

dan*_*987 13

不适用于 Rails 5

Survey.skip_callback(:save, :before, :calculate_average) 
Run Code Online (Sandbox Code Playgroud)

适用于 Rails 5

Survey.skip_callback(:save, :before, :calculate_average, raise: false)
Run Code Online (Sandbox Code Playgroud)

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


Ahm*_*ain 12

update_column是一个ActiveRecord不运行任何回调的函数,它也不运行验证.

  • 看起来像`update_all`是类似的,允许我一次更新多个列. (3认同)
  • update_column仅调用update_columns(复数)。如果您要跳过* all *回调和验证,这是不进行验证或回调而进行保存的正确方法。这对于仅翻转布尔值的事情非常有用。还可以检查方法touch,它只会更新updated_at列。 (2认同)

Swa*_*aps 6

如果您想在检查每个调查后有条件地跳过回调,您可以编写自定义方法。

例如。

修改回调

before_save :calculate_averages, if: Proc.new{ |survey| !survey.skip_callback }
Run Code Online (Sandbox Code Playgroud)

新实例方法

def skip_callback(value = false)
  @skip_callback = @skip_callback ? @skip_callback : value
end
Run Code Online (Sandbox Code Playgroud)

用于更新调查的脚本

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
Run Code Online (Sandbox Code Playgroud)

它有点黑客,但希望对你有用。


She*_*Goh 2

希望这就是您正在寻找的。

/sf/answers/461128251/

对于你的第二个问题,我怀疑最好检查一下何时需要进行此计算,如果可以在网络流量处于低谷的指定时间批量处理,那就最好了。

编辑:哎呀。我实际上找到了 2 个链接,但显然丢失了第一个链接。希望你已经修好了。