如何为特定用户skip_callback before_save?

时间:2015-11-18 07:44:06

标签: ruby-on-rails ruby ruby-on-rails-4 devise rails-activerecord

我的update中有一个名为DailyOrdersController的方法:

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回调。

我使用Devise gem生成了2个用户模型:

  1. 用户(有current_user
  2. 管理员(有current_admin
  3. 我试着这样做:

    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回调。

    我现在该怎么办?

2 个答案:

答案 0 :(得分:2)

答案 1 :(得分: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_columns 。 以下是documentation of the method中的内容:

  

直接在发出UPDATE SQL的数据库中更新属性     声明并将它们设置在接收器中:

     

user.update_columns(last_request_at:Time.current)

     

这是更新属性的最快方法,因为它直接进行     数据库,但考虑到因此定期更新     程序完全被绕过。特别是:

     
      
  • \跳过验证。
  •   
  • \跳过回调。
  •   
  • + updated_at + / + updated_on +未更新。

         

    当在new上调用时,此方法引发ActiveRecord :: ActiveRecordError   对象,或至少有一个属性被标记为只读时。

  •