Rails 4:如何取消保存"before_save"回调?

big*_*ato 23 ruby-on-rails

我有复杂的模型/表格.我不想重复记录,所以我想合并具有相似属性的记录.如何使用before_save回调取消"保存"?这就是我的想法:

class ProductsColor < ActiveRecord::Base


  before_save :check_for_similar_record

  def check_for_similar_record
    if ProductsColor.exist?(color_id: self.color_id, product_id: self.product_id)
      # merge values with existing ProductsColor and stop self from saving
    end
  end

end
Run Code Online (Sandbox Code Playgroud)

mea*_*gar 63

Rails 5

从Rails 5开始,您可以通过显式调用throw :abort回调内部来表示应该中止操作.取消回调(现在)的文档部分指出:

如果before_*回调throws :abort,则取消所有后续回调和相关操作.

以下关于交易的部分继续:

如果before_*回调取消了动作a,ROLLBACK则发出.您还可以ROLLBACK在任何回调中触发引发异常,包括after_*挂钩.

Rails 4

这个故事非常类似于Rails 5,除了回调应该返回false.文档的相应部分有助于说明

如果before_*回调返回false,则取消所有后续回调和相关操作.如果after_*回调返回false,则取消所有后续回调.

其次是

如果before_*回调取消了动作a ROLLBACK.您还可以在任何回调中触发ROLLBACK引发异常,包括after_*hooks.

  • 如果你想让它静静地不保存怎么办?例如,防止关联表中的重复关联.在这种情况下无需抛出错误... Rails 5 (5认同)
  • 另请参阅:**Rails 5 throw abort:我如何设置错误消息?** http://stackoverflow.com/questions/38625276/rails-5-throw-abort-how-do-i-setup-error-messages (3认同)

Mar*_*pka 32

要防止记录被保存,您只需返回false:

def check_for_similar_record
  if ProductsColor.exists?(color_id: self.color_id, product_id: self.product_id)
    # merge values
    false
  else
    true
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 如果返回nil,记录仍将保存,您必须显式返回false才能取消保存. (11认同)
  • 从Rails 5开始不再如此 - 有关详细信息,请参阅其他答案. (3认同)