【问题标题】:rails 3 : Do i need to give return true in a before_save callback for an object.save to work?rails 3:我是否需要在 before_save 回调中返回 true 才能使 object.save 工作?
【发布时间】:2011-06-11 17:33:47
【问题描述】:
Class User  
  before_save :set_searchable

  def set_searchable  
    self.searchable = true if self.status == :active  
  end  
end  

>> u = User.last  
>> u.save  
false  

u.save 总是返回 false。如果我删除 before_save 它可以工作 如果我在 before_save 中返回 true,它也可以工作

所以我需要在 before_save 中给出返回语句吗? 如果 before_save 返回 false,ActiveRecord 会保存对象吗?

我在哪里可以看到有关回调及其工作流程的完整文档。

提前致谢

【问题讨论】:

  • 接受的答案应该修改为@mahemoff的

标签: ruby ruby-on-rails-3 activerecord callback


【解决方案1】:

另一种设置布尔列而不使用return 的更简洁方法是使用tap

  def set_searchable
    self.tap{|u| u.searchable = status.eql?(:active) }
  end

【讨论】:

    【解决方案2】:

    不,您不需要从 Rails 回调中返回 true。您可以不返回任何内容、true 或 3.141592,它仍然会被保存。唯一重要的是如果您返回 false,这仅适用于 Rails 5 之前。返回 false 将取消在 Rails 5 之前的保存。返回 true 从来没有任何效果。

    对于 Rails 5+,阻止更新的新方法是抛出异常:throw(:abort).。这更直观,更不容易出错。返回值对是否保存没有影响,除非您配置旧的行为。

    这是有效的 - 并且是良好的 DRY 做法 - 继续您的业务而不返回任何东西;如果使用早期的 Rails,请确保避免意外返回 false 隐式。例如:

    # This is fine, record will be saved
    def before_save
      self.foo = 'bar' # Implicitly returns 'bar'
    end
    
    # This is an accidental veto, record will not be saved
    def before_save
      Rails.logger.info 'user requested save'
      self.fresh = false # Oops! Implicitly returns false
    end
    
    # One way to rectify the above example (another would be to re-order if it's possible)
    def before_save
      Rails.logger.info 'user requested save'
      self.fresh = false
      return # Implicitly returns nil. Could also do `return true`
    end
    

    这里的问题是你可能会忘记一些“过程”类型的函数会返回一个布尔值作为一种状态代码,或者仅仅是因为实现碰巧以一个布尔值作为副作用结束。你可能认为你正在改变一个字符串或其他东西,但最终意外地否决了回调。因此,虽然我认为从回调显式返回通常太嘈杂,但您确实需要注意隐式返回。人们提倡返回 true 的一个原因是要提防这个问题。

    【讨论】:

      【解决方案3】:

      文档说

      如果 before_* 回调返回 false,则所有后面的回调和 相关动作被取消。如果 after_* 回调返回 false, 所有后来的回调都被取消了。回调通常运行在 它们被定义的顺序,除了回调定义为 模型上的方法,最后调用。

      但是

      你可能想检查这个out(我自己测试过这个问题是 100% 真实的)

      另外还有一个与 before_save 相关的错误,您可能想知道查看here 上的评论

      正如评论中所说,有时会观察到它。

      无论您做什么,只要意识到 rails 回调存在一些问题。当您遇到其中之一时,这将节省您的时间

      【讨论】:

      • 这是否意味着当我在 before_save/before_update 回调 (self.attr = new_val) 中更改一个属性时,它有时不会保存它?
      • 不,这意味着如果在其他对象上有.save.update_attributes,它将刷新当前对象sometime 的哈希(这很重要,因为它不会一直发生)并且不会保存执行 before_save 的当前记录本身
      • 这确定是一个错误吗?
      【解决方案4】:

      发件人:http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

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

      所以,是的。

      【讨论】:

      • 谢谢面条。我在哪里可以看到有关回调及其工作流程的完整文档。
      • @noodl 文档有些问题,请检查我的答案
      • 重要提示:请注意,在 Rails 5 中返回 false 不再有效,请参阅下面@mahemoff 的答案。
      猜你喜欢
      • 2013-12-24
      • 2017-06-12
      • 1970-01-01
      • 2012-02-03
      • 2021-09-04
      • 2015-07-19
      • 1970-01-01
      • 1970-01-01
      • 2014-07-27
      相关资源
      最近更新 更多