【问题标题】:Save Model with a partially failed validation保存验证部分失败的模型
【发布时间】:2013-09-05 18:44:20
【问题描述】:

假设我有以下模型:

class Car < ActiveRecord::Base

attr_accessible :wheels,
                :engine_cylinders

validates :wheels, :engine_cylinders, presence: true, numericality: true

end

假设我有以下控制器操作:

@car = Car.find(params[:id])
@car.wheels = "foo"
@car.engine_cylinders = 4
@car.save

此保存将失败,因为车轮将无法满足数字条件。

有什么方法可以保留成功的属性(在本例中为 engine_cylinders),同时将无效的属性添加到错误数组中?例如。 Rails 中是否有“软”验证?

【问题讨论】:

  • 这确实应该澄清(例如“propogate”的定义)。另外,请注意,验证通过填充errors 数组与save 机制进行通信,因此任何向该数组添加内容的验证都将禁止任何后续保存。
  • 虽然“传播到磁盘”是一个常见的想法,但“持久”可能是更标准的措辞。

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


【解决方案1】:

你想写一个Custom Validator

class Car < ActiveRecord::Base
  validate :wheel_range,
           :engine_cylinder_range

  def engine_cylinder_range
    flash[:notice] = "engine_cylinder was not saved because it wasn't a number" unless engine_cylinder.is_a? Fixnum
    # set engine_cylinder back to old value
  end

  def wheel_range
    flash[:notice] = "wheels was not saved because it wasn't a number" unless wheels.is_a? Fixnum
    # set wheels back to old value
  end
end

您不必在这里使用flash,您可以使用任何变量进行内部处理或重新显示。

您可能还希望将此自定义验证检查放在:before_save hook 上。使用_was magic method 获取旧值。

【讨论】:

  • 自定义验证方法不应该提出,而是errors.add(:attr, ...)。而且他们绝对不应该提出任何继承自Exception 的东西。 StandardError 的后代是应用程序级别的错误,而从 Exception 继承的其他错误是关于环境的。没有类型的普通rescue 也不会捕捉到后者。
  • @TeroTilus 我认为添加错误会阻止保存,OP 希望确保在所有情况下都发生这种情况。所以 errors.add 然后是 self.save ?显然我们希望这种验证处理发生在验证器中,否则我们将在代码中乱扔log 'zzz' unless something.valid?; something.save(validate: false),这只是一团糟
  • 它确实阻止了保存。所以肯定会引发错误。正如@pdobb 已经指出的那样,当他想要检查有效性时,他应该使用@car.valid?,而当他想要保存绕过验证时应该使用@car.save(:validate =&gt; false)
  • @TeroTilus 再次阅读问题:OP希望传播有效的属性,并警告/警告/通知其他人不保存它们
  • 您是否将“传播”理解为“保存”,因为我将其解释为“通知某人”。如果你这样做了,那再加上你不加注的答案是有道理的。
【解决方案2】:

如果您希望绕过验证,您可以随时这样做:

if @car.save
  # ...
else
  @car.save(validate: false)
end

您可能希望对此有不同的条件或其他...但这是您一次性绕过验证的方式。

但是,这可能会破坏错误数组,以便您可以在 save(validate: false) 之后重建它:

@car.valid?

您还可以使用 @car.update_attribute(:attribute, &lt;value&gt;) 一次绕过验证。

【讨论】:

    【解决方案3】:

    如果您只是想知道模型是否有效而不保存它,@car.valid? 正是这样做的。它还将无效属性添加到错误数组。并且@pdobb 已经指出了如何在保存时绕过验证。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-26
      • 2015-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多