我正在尝试将自定义错误添加到我的用户模型的实例中,但是当我调用有效时?它正在擦除自定义错误并返回true。
[99] pry(main)> u.email = "test@test.com"
"test@test.com"
[100] pry(main)> u.status = 1
1
[101] pry(main)> u.valid?
true
[102] pry(main)> u.errors.add(:status, "must be YES or NO")
[
[0] "must be YES or NO"
]
[103] pry(main)> u.errors
#<ActiveModel::Errors:[...]@messages={:status=>["must be YES or NO"]}>
[104] pry(main)> u.valid?
true
[105] pry(main)> u.errors
#<ActiveModel::Errors:[...]@messages={}>
如果我在模型中使用validate
方法,那么它可以工作,但是这个特定的验证是从不同的方法中添加的(这需要传递参数):
User
def do_something_with(arg1, arg2)
errors.add(:field, "etc") if arg1 != arg2
end
由于上述原因,user.valid?即使将错误添加到实例中,也会返回true。
答案 0 :(得分:43)
在ActiveModel中,valid?
定义如下:
def valid?(context = nil)
current_context, self.validation_context = validation_context, context
errors.clear
run_validations!
ensure
self.validation_context = current_context
end
预计会清除现有错误。您必须将所有自定义验证放入一些validate
回调中。像这样:
validate :check_status
def check_status
errors.add(:status, "must be YES or NO") unless ['YES', 'NO'].include?(status)
end
答案 1 :(得分:1)
如果您想强制模型显示错误,可以执行以下操作脏:
your_object = YourModel.new
your_object.add(:your_field, "your message")
your_object.define_singleton_method(:valid?) { false }
# later on...
your_object.valid?
# => false
your_object.errors
# => {:your_field =>["your message"]}
define_singleton_method
方法可以覆盖.valid?
行为。
答案 2 :(得分:0)
这不能代替使用提供的验证/框架。但是,在某些 exception 方案中,您希望优雅地返回错误的模型。如果无法使用其他替代方法,我会仅使用此功能。我必须使用这种方法的少数情况之一是在服务对象内部创建模型,该模型中部分创建失败(例如解决从属实体)。我们的域模型负责这种类型的验证是没有意义的,因此我们不将其存储在此处(这就是为什么服务对象首先要进行创建的原因)。但是,为了简化API设计,可以方便地挂起“未找到关联实体foo”之类的域错误,然后通过正常的422 /不可处理的实体流返回。
--smart
用作class ModelWithErrors
def self.new(*errors)
Module.new do
define_method(:valid?) { false }
define_method(:invalid?) { true }
define_method(:errors) do
errors.each_slice(2).with_object(ActiveModel::Errors.new(self)) do |(name, message), errs|
errs.add(name, message)
end
end
end
end
end
答案 3 :(得分:0)
引起新的关注
app / models / concerns / static_error.rb
module StaticError
extend ActiveSupport::Concern
included do
validate :check_static_errors
end
def add_static_error(*args)
@static_errors = [] if @static_errors.nil?
@static_errors << args
true
end
def clear_static_error
@static_errors = nil
end
private
def check_static_errors
@static_errors&.each do |error|
errors.add(*error)
end
end
end
包括模型
class Model < ApplicationRecord
include StaticError
end
model = Model.new
model.add_static_error(:base, "STATIC ERROR")
model.valid? #=> false
model.errors.messages #=> {:base=>["STATIC ERROR"]}
答案 4 :(得分:-1)
实现您需求的一种简洁方法是上下文,但如果您想快速解决问题,请执行以下操作:
#in your model
attr_accessor :with_foo_validation
validate :foo_validation, if: :with_foo_validation
def foo_validation
#code
end
#where you need it
your_object.with_foo_validation = true
your_object.valid?