【问题标题】:Rails - Cancel destroy on before_destroy callbackRails - 在 before_destroy 回调上取消销毁
【发布时间】:2016-06-14 19:50:35
【问题描述】:

在特定条件下,有没有办法在活动记录的 before_destroy 回调中取消对象的销毁?谢谢

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    你应该返回false

    导轨 5

    "取消回调

    如果 before_* 回调抛出 :abort,所有后面的回调和相关的操作都会被取消。"

    导轨 4 及以下

    "取消回调

    如果 before_* 回调返回 false,则所有后面的回调和相关操作都将被取消。回调通常按照定义的顺序运行,但定义为模型上的方法的回调除外,这些方法最后调用。”

    Source

    【讨论】:

    • 在 Rails 5 中,返回 false 不再有效。应该throw(:abort) 以防止记录删除。见this comment
    • 感谢您为 Rails 5 指定 :abort 技术。真的可以帮到我。
    • 我一直在寻找这个答案——官方文档api.rubyonrails.org/classes/ActiveRecord/…甚至都不清楚——谢谢!
    • 对于 rails 3,返回 false 只是跳过其他回调,但它会破坏实际对象。有人吗?
    【解决方案2】:

    由于没有一个给出的答案真正解决了问题,但上面的评论告诉了它 - 这里是一个答案的形式,以便于找到:

    在 rails 5 中,而不是

    before_destroy do
      if self.some_condition?
        return false
      end
    end
    

    使用

    before_destroy do
      if self.some_condition?
        throw(:abort)
      end
    end
    

    确保没有执行销毁。

    感谢RFVoltolini's comment - 这拯救了我的一天!

    【讨论】:

      【解决方案3】:

      Rails 在事务中包装保存和销毁,因此回调中的 raise 可以工作:

      class Post < ActiveRecord::Base
        before_destroy :saveable?
      
        def saveable?
          if true
            raise "Destroy aborted; you can't do that!"
          end
        end
      end
      

      true 替换为您的情况。

      这是精简的控制台输出:

      [1] pry(main)> Post.first.id
      => 1
      [2] pry(main)> Post.first.destroy
      RuntimeError: Destroy aborted; you can't do that!
      [3] pry(main)> Post.first.id
      => 1
      

      Documentation

      【讨论】:

      • 谢谢,但不希望它引发任何事情......什么也不做
      • 有道理。因为这是一个before_* 回调,所以raisefalse 都可以。 raise 的好处是您将获得可以在日志中跟踪的明确消息,而不是 destroy 悄悄地没有发生。选择哪一个取决于您的失败案例的意外程度。
      • 在 Rails 5 中,你必须明确地raise :abort。你不妨现在就开始。
      • 在 Rails 5 中,raise :abort 对我不起作用。我认为它必须throw :abort
      【解决方案4】:

      返回false 是正确的方法:

      before_destroy do
        if self.some_condition?
          return false
        end
      end
      

      您可以在6 Halting Execution 点下查看文档。 http://guides.rubyonrails.org/active_record_callbacks.html

      【讨论】:

        【解决方案5】:

        您还可以覆盖#destroy 方法:

        def destroy
          study_assignments.empty? ? super : raise("can not be destroyed")
        end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-16
          • 1970-01-01
          • 2017-02-21
          • 1970-01-01
          相关资源
          最近更新 更多