如何在更新属性之前添加错误?
How to add errors before updating attributes?
我正在尝试处理用户输入错误信息的情况,所以我的路径大致如下:
class Thing < AR
before_validation :byebug_hook
def byebug_hook
byebug
end
end
thing = Thing.find x
thing.errors.add(:foo, "bad foo")
# Check byebug here, and errors added
if thing.update_attributes(params)
DelayedJobThatDoesntLikeFoo.perform
else
flash.now.errors = #...
end
byebug for byebug_hook> errors.messages #=> {}
最初我认为也许模型是 运行 它自己的验证并覆盖了我添加的那些,但是正如你所看到的,即使我添加了 before 钩子,错误也不见了,我不是确定是什么原因造成的
实际解决方案
所以,@SteveTurczyn 是正确的,错误需要发生在某个地方,在这种情况下是在我的控制器中调用的服务对象
我所做的更改是
class Thing < AR
validate :includes_builder_added_errors
def builder_added_errors
@builder_added_errors ||= Hash.new { |hash, key| hash[key] = [] }
end
def includes_builder_added_errors
builder_added_errors.each {|k, v| errors.set(k, v) }
end
end
and in the builder object
thing = Thing.find x
# to my thinking this mirrors the `errors.add` syntax better
thing.builder_added_errors[:foo].push("bad foo") if unshown_code_does_stuff?
if thing.update_attributes(params)
DelayedJobThatDoesntLikeFoo.perform
else
flash.now.errors = #...
end
update_attributes
将验证模型...这包括清除所有现有错误,然后 运行 任何 before_validation 回调。这就是为什么 before_validation
的桥接点永远不会出现任何错误的原因
如果您想向 "normal" 验证错误添加错误条件,最好将其作为模型中的自定义验证方法来执行。
class Thing < ActiveRecord::Base
validate :add_foo_error
def add_foo_error
errors.add(:foo, "bad foo")
end
end
如果您希望某些验证仅在某些控制器或条件下发生,您可以通过在模型上设置一个 attr_accessor
值,并在 运行 验证之前直接设置一个值来实现( :valid?) 或间接 (:update, :save).
class Thing < ActiveRecord::Base
attr_accessor :check_foo
validate :add_foo_error
def add_foo_error
errors.add(:foo, "bad foo") if check_foo
end
end
在控制器中...
thing = Thing.find x
thing.check_foo = true
if thing.update_attributes(params)
DelayedJobThatDoesntLikeFoo.perform
else
flash.now.errors = #...
end
我正在尝试处理用户输入错误信息的情况,所以我的路径大致如下:
class Thing < AR
before_validation :byebug_hook
def byebug_hook
byebug
end
end
thing = Thing.find x
thing.errors.add(:foo, "bad foo")
# Check byebug here, and errors added
if thing.update_attributes(params)
DelayedJobThatDoesntLikeFoo.perform
else
flash.now.errors = #...
end
byebug for byebug_hook> errors.messages #=> {}
最初我认为也许模型是 运行 它自己的验证并覆盖了我添加的那些,但是正如你所看到的,即使我添加了 before 钩子,错误也不见了,我不是确定是什么原因造成的
实际解决方案 所以,@SteveTurczyn 是正确的,错误需要发生在某个地方,在这种情况下是在我的控制器中调用的服务对象
我所做的更改是
class Thing < AR
validate :includes_builder_added_errors
def builder_added_errors
@builder_added_errors ||= Hash.new { |hash, key| hash[key] = [] }
end
def includes_builder_added_errors
builder_added_errors.each {|k, v| errors.set(k, v) }
end
end
and in the builder object
thing = Thing.find x
# to my thinking this mirrors the `errors.add` syntax better
thing.builder_added_errors[:foo].push("bad foo") if unshown_code_does_stuff?
if thing.update_attributes(params)
DelayedJobThatDoesntLikeFoo.perform
else
flash.now.errors = #...
end
update_attributes
将验证模型...这包括清除所有现有错误,然后 运行 任何 before_validation 回调。这就是为什么 before_validation
如果您想向 "normal" 验证错误添加错误条件,最好将其作为模型中的自定义验证方法来执行。
class Thing < ActiveRecord::Base
validate :add_foo_error
def add_foo_error
errors.add(:foo, "bad foo")
end
end
如果您希望某些验证仅在某些控制器或条件下发生,您可以通过在模型上设置一个 attr_accessor
值,并在 运行 验证之前直接设置一个值来实现( :valid?) 或间接 (:update, :save).
class Thing < ActiveRecord::Base
attr_accessor :check_foo
validate :add_foo_error
def add_foo_error
errors.add(:foo, "bad foo") if check_foo
end
end
在控制器中...
thing = Thing.find x
thing.check_foo = true
if thing.update_attributes(params)
DelayedJobThatDoesntLikeFoo.perform
else
flash.now.errors = #...
end