0

我有我的DailyOrdersController內一個名爲update方法:如何爲特定用戶skip_callback before_save?

def update 
    if @daily_order.update(daily_order_params.merge({default_order:false})) 
     respond_or_redirect(@daily_order) 
    else 
     render :edit 
    end 
end 

DailyOrder型號:

before_save :refresh_total 

def refresh_total 
    # i do something here 
end 

什麼我想現在要做的是,我希望refresh_total回調被跳過,如果更新請求來自current_admin

我使用設計的寶石產生2的用戶模型:

  1. 用戶(擁有current_user
  2. 管理員(具有current_admin

我儘量讓這樣的:

def update 
    if current_admin 
     DailyOrder.skip_callback :update, :before, :refresh_total 
    end 

    if @daily_order.update(daily_order_params.merge({default_order:false})) 
     respond_or_redirect(@daily_order) 
    else 
     render :edit 
    end 
end 

但它不工作,仍然保持呼叫refresh_total回叫如果更新請求來自current_admin(當登錄用戶是管理員用戶時)。

現在該怎麼辦?

回答

0

如果你跳過回調,你應該稍後再啓用。無論如何,這看起來並不是最好的解決方案。也許你可以避免這種回調。

一種方法是使用update_all:

DailyOrder.where(id: @daily_order.id).update_all(daily_order_params.merge({default_order:false})) 

或者你可以做這樣的事情:

#in the model: 
before_validation :refresh_total 

#in the controller 
@daily_order.assign_attributes(daily_order_params.merge({default_order:false})) 
@daily_order.save(validate: current_admin.nil?) 

也許這將是最好的一個新列添加到模型: refresh_needed然後你有條件地更新before_validation上的那一列,before_save你仍然會調用相同的回調函數,但是有條件地返回到refresh_needed狀態。在此回調中,您應該重置該列。請讓我知道你是否希望我用一些代碼來說明這一點。


這可能會派上用場: http://www.davidverhasselt.com/set-attributes-in-activerecord/


UPDATE

更妙的是,你可以叫update_columns。 下面是它在documentation of the method說:

直接更新的屬性數據庫發出UPDATE SQL語句 並設定他們在接收器:

user.update_columns(last_request_at:Time.current)

這是更新屬性的最快方式,因爲它直接到 數據庫,但是考慮到因此定期更新 程序完全被繞過。特別是:

  • \驗證被跳過。
  • \回調被跳過。
  • + updated_at +/+ updated_on +不會更新。

    當在新的 對象上調用時,或者至少有一個屬性標記爲只讀時,此方法會引發ActiveRecord :: ActiveRecordError。