在Rails验证中使用ActiveModel::Dirty。

问题描述 投票:1回答:1

我试图在我的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和验证的理解,或者提供一个比我刚才列举的更好的方法,我将接受你的答案。但现在这个办法可以用,所以我就顺其自然了。谢谢你。

ruby-on-rails validation ruby-on-rails-5 activemodel
1个回答
0
投票

方法的目的是 [attribute]_will_change! 并不是为了呈现什么属性,而是为了标记一个类的对象的属性,其中包括了 ActiveModel::Dirty(在你的例子中,一个轨道模型类),它

这个属性要发生变化,请将变化记录在 changes 属性 (ActiveModel::Dirty)

发送后 [attr]_will_change! 到对象, [attr]_wasobject.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"  }

© www.soinside.com 2019 - 2024. All rights reserved.