Rails errors.add override:无法创建语言文件条目

时间:2015-01-03 06:26:01

标签: ruby-on-rails validation symbols

我正在努力解决我的问题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”),我收到以下错误:

  • 群组代码我的自定义消息www不合适。
  • 组代码自定义错误
  • 组代码我的自定义消息www不合适。

如果我没有提供自定义错误消息:

validates :group_code, existing_two: true

对于无效输入(例如“www”),我收到以下错误:

  • 组代码无效
  • 组代码自定义错误
  • 缺少组代码转换:en.activerecord.errors.models。 XX .attributes.group_code.madeup

第一个record.errors.add(attribute, :invalid, ...将允许我覆盖默认消息:invalid,但如果我提供文字字符串作为第二个参数(例如record.errors.add(attribute, "custom error",它将不允许我覆盖该消息。< / p>

我想理解这样的逻辑:如果它是一个符号,它可以被替换,但如果它的字符串忽略了选项中传递的消息。另外,有没有办法在不使用符号的情况下提供自定义消息,或者有没有办法定义符号而不将其添加到某个语言文件?

2 个答案:

答案 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

我强烈建议您阅读我提供的源代码链接,因为它有详细记录并且非常深入。

Active Model Errors

答案 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