我试图在我的Model验证中使用Rails ActiveModel::Dirty来要求某些字段的存在,具体取决于 status
我的记录曾经或将会是。
当前验证
validates :pause_reason, presence: true, if: Proc.new { |o| o.status_will_change! == "Paused" }
validates :unpause_reason, presence: true, if: Proc.new { |o| o.status_was == "Paused" }
所以 pause_reason
验证似乎工作得很好,比如当我把状态改为 Paused
而留下 pause_reason
空白,我得到了相应的错误 "Pause Reason cannot be blank",同样,如果我填写上述字段,我也不会得到该错误。
然而,当我尝试保存同样的更改时,该 unpause_reason
validation也出现了 "Unpause reason cannot be blank "的错误。我试着在rails控制台中进行步骤,结果如下。
irb(main):026:0> o.status
=> "Open"
irb(main):027:0> o.status = "Paused"
=> "Paused"
irb(main):028:0> o.status_will_change!
=> nil ## should be "Paused" I think
irb(main):029:0> o.status_was
=> "Open"
irb(main):030:0> o.status_was == "Paused"
=> false
irb(main):031:0> o.pause_reason
=> nil
irb(main):032:0> o.valid?
=> true ## should be false
所以我想我有点糊涂了 到底在验证过程中发生了什么,会导致这个错误 pause_reason
验证,以(看似)如愿以偿地工作,但也没有通过 unpause_reason
当控制台清楚地显示 status_was
相当于 "Open"
.
如果有人能帮助我了解如何在Rails验证中适当地使用ActiveModel::Dirty,我将非常感激。
更新
经过更多的研究,我决定将我的 "状态验证 "组合成一个单一的方法,验证在 update
如下。
validates :status_change_validations, on: :update
def status_change_validations
if status == "Paused" && pause_reason.blank?
errors.add(:pause_reason, 'required when pausing an order.')
elsif status != "Paused" && status_was == "Paused" && unpause_reason.blank?
errors.add(:unpause_reason, 'required when resuming an order.')
elsif status == "Canceled" && cancellation_reason.blank?
errors.add(:cancellation_reason, 'required when canceling an order.')
elsif status != "Canceled" && status_was == "Canceled" && reopen_reason.blank?
errors.add(:reopen_reason, 'required when reopening an order.')
elsif status == "Reactivate" && reactivation_reason.blank?
errors.add(:reactivation_reason, 'required when reactivating an order.')
end
end
这似乎与我的意图完全一致 虽然,我还是不明白为什么原来的单行验证要用... Procs
不起作用。如果有人还想用一个可行的答案来解释这个问题,以加深我对procs和验证的理解,或者提供一个比我刚才列举的更好的方法,我将接受你的答案。但现在这个办法可以用,所以我就顺其自然了。谢谢你。
方法的目的是 [attribute]_will_change!
并不是为了呈现什么属性,而是为了标记一个类的对象的属性,其中包括了 ActiveModel::Dirty
(在你的例子中,一个轨道模型类),它
这个属性要发生变化,请将变化记录在
changes
属性 (ActiveModel::Dirty)
发送后 [attr]_will_change!
到对象, [attr]_was
或 object.changes
或其他方法 ActiveModel::Dirty
可以正确应对。
所以你的问题的总结,没有什么问题。proc
在那里,但你使用的方式 [attr]_will_change!
. 如果我没弄错的话,你想做的应该是这样的。
validates :pause_reason, presence: true, if: Proc.new { |o| o.status == "Paused" }
validates :unpause_reason, presence: true, if: Proc.new { |o| o.status_was == "Paused" }