17

我需要在Rails中保存模型時計算值。所以,我呼籲calculate_averages作爲一個Survey類的回調:如何保存模型而無需在Rails中運行回調

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得到調用並做它的事情。問題在於,首先,是否有辦法強制回調被調用,即使您沒有對記錄進行任何更改?

其次,平均值的計算方法是效率更高,根本不會讓回調被調用,並一次完成所有事情的平均值。這可能不會讓回調被調用?

+3

如果你有10k條記錄要更新,那麼爲什麼不完全繞過AR,只做一個簡單的SQL UPDATE?特別是如果你想跳過回調。 –

+0

@ muistooshort - 我簡化了我需要做的計算,但它們很複雜,也取決於其他記錄。我需要Ruby。 –

回答

0

希望這是你要找的。

https://stackoverflow.com/a/6587546/2238259

對於你的第二個問題,我懷疑這會更好時,這種計算需要發生檢查,這將是最好的,如果它可以在批量在指定的時間,其中的網絡流量是在其被處理槽。

編輯:Woops。實際上,我發現了2個鏈接,但顯然丟失了第一個鏈接。希望你修好了。

+0

第一個鏈接是完全不相關的東西。儘管第二個鏈接是信息性的,但看起來我最好的選擇是使用'survey.update_all(field:value)'機制,因爲它在更新後不會調用回調。 –

6

要禁用EN-質量回調使用...

Survey.skip_callback(:calculate_averages) 

然後讓他們...

Survey.set_callback(:calculate_average) 

此跳過/套所有實例。

+0

似乎它可能不會調用回調,即使我希望它們(如果在重新計算平均值的過程中創建新記錄)? –

+0

您可以在迭代收集的動作周圍使用這兩個調用。暫時禁用特定的call_back以提高性能。 – rafroehlich2

+0

我明白這個過程,但是當我需要他們在那個時間窗口期間被調用時,這不會讓我打電話回調嗎? –

6

update_column是一個ActiveRecord函數,它不運行任何回調,也不運行驗證。

+2

看起來像'update_all'類似,允許我一次更新多個列。 –

+0

update_column適用於一個記錄 –

+0

是的,令人討厭的是,我必須爲每條記錄進行15次sql更新調用。 –

12

我相信你所要求的可以用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). 

請參考鏈接ActiveSupport::Callbacks上支持的其他選項,如條件和塊set_callbackskip_callback

+0

爲什麼註冊回調強制回調被調用,即使你沒有改變它? –

+0

改變不是唯一可能觸發回調的事件。因爲一個事件被註冊爲回調,回調預計會被調用,不是嗎? – vee

+0

什麼其他更改可以觸發'before_save'回調? –

0

For Rails 3 ActiveSupport::Callbacks爲您提供必要的控制。您可以reset_callbacks EN-集體,或使用skip_callback明智地禁止這樣的:

Vote.skip_callback(:save, :after, :add_points_to_user) 

…之後,您可以在投票情況與:add_points_to_user抑制

0

如果你想檢查後,有條件地跳過回調操作每次調查都可以編寫自定義方法。

例如,修改callback-

`

  • before_save :calculate_averages, if: Proc.new{ |survey| !survey.skip_callback } 
    

    `

    • 新實例方法 -

    `

    def skip_callback(value = false) 
        @skip_callback = @skip_callback ? @skip_callback : val 
    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 
    

    `

    它有點本事,但希望會爲你工作。

相關問題