I need to calculate values when saving a model in Rails. So I call calculate_averages
as a callback for a Survey
class:
在Rails中保存模型时,我需要计算值。因此我将calculate_average调用为一个调查类的回调:
before_save :calculate_averages
However, occasionally (and initially I have 10k records that need this operation) I need to manually update all the averages for every record. No problem, I have code like the following:
然而,偶尔(最初我有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
Before even running this code, I'm worried the calculate_averages
is going to get called and duplicate this and probably even cause some problems with the way I'm doing things. Ok, so then I think, well I'll just do nothing and let calculate_averages
get called and do its thing. Problem there is, first, is there a way to force callbacks to get called even if you made no changes to the record?
在运行这段代码之前,我担心calculate_average会被调用并重复这个操作,甚至可能会对我的操作方式造成一些问题。然后我想,我什么都不做让calculate_average被调用并执行它。问题是,首先,是否有一种方法可以强制回调被调用,即使您对记录没有做任何更改?
Secondly, the way averages are calculated it's far more efficient to simply not let the callbacks get called at all and do the averages for everything all at once. Is this possible to not let callbacks get called?
其次,计算平均值的方法是不让回调被调用,同时做所有事情的平均值,这样效率会高得多。是否有可能不让回调被调用?
6 个解决方案
#1
13
I believe what you are asking for can be achieved with ActiveSupport::Callbacks
. Have a look at set_callback
and skip_callback
.
我相信您所要求的可以通过ActiveSupport:回调来实现。看看set_callback和skip_callback。
In order to "force callbacks to get called even if you made no changes to the record", you need to register the callback to some event e.g. save, validate etc.
.
为了“强迫回调被调用,即使你没有对记录做任何修改”,你需要注册回调到一些事件,例如保存,验证等等。
set_callback :save, :before, :my_before_save_callback
To skip the before_save
callback, you would do:
要跳过before_save回调,可以这样做:
Survey.skip_callback(:save, :before, :calculate_average).
Please reference the linked ActiveSupport::Callbacks
on other supported options such as conditions and blocks to set_callback
and skip_callback
.
请引用链接的ActiveSupport::对其他受支持选项的回调,比如set_callback和skip_callback的条件和块。
#2
6
To disable en-mass callbacks use...
要禁用en-mass回调,请使用…
Survey.skip_callback(:calculate_averages)
Then to enable them...
然后让他们…
Survey.set_callback(:calculate_average)
This skips/sets for all instances.
这将跳过/设置所有实例。
#3
6
update_column
is an ActiveRecord
function which does not run any callbacks, and it also does not run validation.
update_column是一个ActiveRecord函数,它不运行任何回调,也不运行验证。
#4
2
If you want to conditionally skip callbacks after checking for each survey you can write your custom method.
如果您想在检查完每个调查之后有条件地跳过回调,那么您可以编写定制的方法。
For ex.
前女友。
- Modified callback-
- 修改后的回调,
`
”
before_save :calculate_averages, if: Proc.new{ |survey| !survey.skip_callback }
`
”
- New instance method-
- 新实例方法
`
”
def skip_callback(value = false)
@skip_callback = @skip_callback ? @skip_callback : value
end
`
”
- Script to update surveys-
- 脚本更新调查
`
”
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
`
”
Its kinda hack but hope will work for you.
这是一种技巧,但希望对你有用。
#5
0
hopefully this is what you're looking for.
希望这就是你要找的。
https://*.com/a/6587546/2238259
https://*.com/a/6587546/2238259
For your second issue, I suspect it would be better to inspect when this calculation needs to happen, it would be best if it could be handled in batch at a specified time where network traffic is at its trough.
对于您的第二个问题,我认为最好检查一下何时需要进行这种计算,最好是在网络流量处于低谷的特定时间分批处理。
EDIT: Woops. I actually found 2 links but lost the first one, apparently. Hopefully you have it fixed.
编辑:呕吐。我实际上找到了两个链接,但是丢失了第一个。希望你能修好它。
#6
0
For Rails 3 ActiveSupport::Callbacks
gives you the necessary control. You can reset_callbacks
en-masse, or use skip_callback
to disable judiciously like this:
对于Rails 3 ActiveSupport:::回调函数提供了必要的控制。您可以集体使用reset_callbacks,或者使用skip_callback明智地禁用如下内容:
Vote.skip_callback(:save, :after, :add_points_to_user)
…after which you can operate on Vote instances with :add_points_to_user
inhibited
之后,您可以使用:add_points_to_user抑制对投票实例进行操作
#1
13
I believe what you are asking for can be achieved with ActiveSupport::Callbacks
. Have a look at set_callback
and skip_callback
.
我相信您所要求的可以通过ActiveSupport:回调来实现。看看set_callback和skip_callback。
In order to "force callbacks to get called even if you made no changes to the record", you need to register the callback to some event e.g. save, validate etc.
.
为了“强迫回调被调用,即使你没有对记录做任何修改”,你需要注册回调到一些事件,例如保存,验证等等。
set_callback :save, :before, :my_before_save_callback
To skip the before_save
callback, you would do:
要跳过before_save回调,可以这样做:
Survey.skip_callback(:save, :before, :calculate_average).
Please reference the linked ActiveSupport::Callbacks
on other supported options such as conditions and blocks to set_callback
and skip_callback
.
请引用链接的ActiveSupport::对其他受支持选项的回调,比如set_callback和skip_callback的条件和块。
#2
6
To disable en-mass callbacks use...
要禁用en-mass回调,请使用…
Survey.skip_callback(:calculate_averages)
Then to enable them...
然后让他们…
Survey.set_callback(:calculate_average)
This skips/sets for all instances.
这将跳过/设置所有实例。
#3
6
update_column
is an ActiveRecord
function which does not run any callbacks, and it also does not run validation.
update_column是一个ActiveRecord函数,它不运行任何回调,也不运行验证。
#4
2
If you want to conditionally skip callbacks after checking for each survey you can write your custom method.
如果您想在检查完每个调查之后有条件地跳过回调,那么您可以编写定制的方法。
For ex.
前女友。
- Modified callback-
- 修改后的回调,
`
”
before_save :calculate_averages, if: Proc.new{ |survey| !survey.skip_callback }
`
”
- New instance method-
- 新实例方法
`
”
def skip_callback(value = false)
@skip_callback = @skip_callback ? @skip_callback : value
end
`
”
- Script to update surveys-
- 脚本更新调查
`
”
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
`
”
Its kinda hack but hope will work for you.
这是一种技巧,但希望对你有用。
#5
0
hopefully this is what you're looking for.
希望这就是你要找的。
https://*.com/a/6587546/2238259
https://*.com/a/6587546/2238259
For your second issue, I suspect it would be better to inspect when this calculation needs to happen, it would be best if it could be handled in batch at a specified time where network traffic is at its trough.
对于您的第二个问题,我认为最好检查一下何时需要进行这种计算,最好是在网络流量处于低谷的特定时间分批处理。
EDIT: Woops. I actually found 2 links but lost the first one, apparently. Hopefully you have it fixed.
编辑:呕吐。我实际上找到了两个链接,但是丢失了第一个。希望你能修好它。
#6
0
For Rails 3 ActiveSupport::Callbacks
gives you the necessary control. You can reset_callbacks
en-masse, or use skip_callback
to disable judiciously like this:
对于Rails 3 ActiveSupport:::回调函数提供了必要的控制。您可以集体使用reset_callbacks,或者使用skip_callback明智地禁用如下内容:
Vote.skip_callback(:save, :after, :add_points_to_user)
…after which you can operate on Vote instances with :add_points_to_user
inhibited
之后,您可以使用:add_points_to_user抑制对投票实例进行操作