Rails:如何使用before_save根据另一个字段的值更改字段值?

23

我想根据另一个布尔字段的值将一个布尔字段设置为false。 我尝试使用ActiveRecord模型进行以下操作:

  before_save :reconcile_xvent

  def reconcile_xvent
    self.xvent_hood = false if !self.xvent_plenum?
  end

但这样不起作用。现在,我的许多单元测试都会失败并显示以下信息:

ActiveRecord::RecordNotSaved: ActiveRecord::RecordNotSaved
如何在xvent_plenum为false时将xvent_hood设置为false?
更新
这是有效的代码(其中部分代码来自下面的评论/答案):
before_validation :reconcile_xvent

def reconcile_xvent
  if self.xvent_hood?
    self.xvent_hood = false unless xvent_plenum?
  end
end

我不知道如何在没有 "if self.xvent_hood?" 部分的情况下使其工作...


如果 xvent_hood 需要等于 xvent_plenum,那么你应该只需执行 xvent_hood = xvent_plenum - MurifoX
但它们并不总是相等的。xvent_plenum 应该可以为 true,而 xvent_hood 为 false。 - croceldon
1
尝试使用 unlessunless self.xvent_plenum,否则 self.xvend_hood = false - MurifoX
2个回答

26

before_save仅在验证通过后才会被调用。您需要做的是将reconcile_xvent移到before_validation而不是before_save

如果您将该方法保留在before_save中,那么它将认为xvent_hood为空,如果您有一个检查xvent_hood是否为空的验证,它将在调用before_save之前失败。这可能解释了为什么您会遇到RecordNotSaved错误。

还要记住的另一件事是,如果您有一个布尔属性,也不能使用validate_presence_of。请参见http://alexanderwong.me/post/16084280769/rails-validate-presence-of-boolean-and-arrays-mongoid


这似乎是有效的,但为什么 before_save 认为 xvent_hood 为空? - croceldon
并不是before_save认为xvent_hood为空,我相信发生的情况是在before_save被调用之前就未能通过验证。(假设您已经有了适当的验证,这也是为什么您的记录没有保存的原因) - Ken Li
在这里看到before_save文档的链接会很酷。 - botbot

18
我也遇到了这个问题,第一段代码的问题在于你将xvent_hood的值赋为false,然后被你的before_save方法返回。
根据以下内容:
取消回调 如果一个before_*回调返回false,则所有后续的回调和相关的操作都将被取消。如果一个after_*回调返回false,则所有后续回调都将被取消。回调通常按照定义的顺序运行,但作为模型上的方法定义的回调除外,这些回调在最后调用。
来自http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

这是正确的答案,但是你如何解决问题?在 before_save 回调中如何将布尔值赋为 false? - csi
3
before_save方法中将一个布尔值赋值为false时,请确保在回调结束时显式地返回true。例如:def before_save(record) my_false_bool = false return true end - lyallward
这是我第一次看到Ruby表现得很讨厌,因为它省略了像return这样的常规关键字。天哪,这真令人沮丧。 - sakurashinken

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接