我正在努力解决我的问题another question,我认为我接近解决方案,但我遇到了另一个问题。我正在尝试复制我在rails源代码中找到的代码并修改它以满足我的需求:
我创建了以下自定义验证器:
class ExistingTwoValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless Group.where(:code => value).any?
record.errors.add(attribute, :invalid, options.merge(:value => value))
record.errors.add(attribute, "custom error", options.merge(:value => value))
record.errors.add(attribute, :madeup, options.merge(:value => value))
end
end
end
如果我在模型中提供自定义错误消息:
validates :group_code, existing_two: { message: "My custom message %{value} is not okay."}
对于无效输入(例如“www”),我收到以下错误:
如果我没有提供自定义错误消息:
validates :group_code, existing_two: true
对于无效输入(例如“www”),我收到以下错误:
第一个record.errors.add(attribute, :invalid, ...
将允许我覆盖默认消息:invalid,但如果我提供文字字符串作为第二个参数(例如record.errors.add(attribute, "custom error"
,它将不允许我覆盖该消息。< / p>
我想理解这样的逻辑:如果它是一个符号,它可以被替换,但如果它的字符串忽略了选项中传递的消息。另外,有没有办法在不使用符号的情况下提供自定义消息,或者有没有办法定义符号而不将其添加到某个语言文件?
答案 0 :(得分:1)
# File activemodel/lib/active_model/errors.rb, Line 299
def add(attribute, message = :invalid, options = {})
message = normalize_message(attribute, message, options)
if exception = options[:strict]
exception = ActiveModel::StrictValidationFailed if exception == true
raise exception, full_message(attribute, message)
end
self[attribute] << message
end
#File activemodel/lib/active_model/errors.rb, line 438
def normalize_message(attribute, message, options)
case message
when Symbol
generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS))
when Proc
message.call
else
message
end
end
# File activemodel/lib/active_model/errors.rb, line 412
def generate_message(attribute, type = :invalid, options = {})
type = options.delete(:message) if options[:message].is_a?(Symbol)
if @base.class.respond_to?(:i18n_scope)
defaults = @base.class.lookup_ancestors.map do |klass|
[ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
:"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
end
else
defaults = []
end
defaults << options.delete(:message)
defaults << :"#{@base.class.i18n_scope}.errors.messages.#{type}" if @base.class.respond_to?(:i18n_scope)
defaults << :"errors.attributes.#{attribute}.#{type}"
defaults << :"errors.messages.#{type}"
defaults.compact!
defaults.flatten!
key = defaults.shift
value = (attribute != :base ? @base.send(:read_attribute_for_validation, attribute) : nil)
options = {
default: defaults,
model: @base.model_name.human,
attribute: @base.class.human_attribute_name(attribute),
value: value
}.merge!(options)
I18n.translate(key, options)
end
您正在调用 errors.add ,它调用私有方法 normalize_message , normalise_message 方法接收消息,如果它是符号调用 generate_message 。在 generate_message 方法中,它最终会回退到默认消息,因为它无法在 activemodel.errors.models.MODEL.attributes.ATTRIBUTE.MESSAGE 中找到转换,或者 activemodel.errors.models.MODEL.MESSAGE
我强烈建议您阅读我提供的源代码链接,因为它有详细记录并且非常深入。
答案 1 :(得分:0)
这就是你如何才能做到这一点
class Example < ActiveRecord::Base
validates :group_code, presence: true
validate do |example|
unless Group.where(:code => example.group_code).any?
example.errors.add(:base, "The code you have entered #{example.group_code} is not a valid code, please check with your teacher or group")
end
end
end
当然,您也可以提取上述逻辑并将其放入自定义验证器中。
请注意,我正在通过:base
而不是attribute
。
基本上,插值是用i18n gem完成的。
您可以看到here