class ActiveModel::Error

Represents one single error
= Active Model Error

def self.full_message(attribute, message, base) # :nodoc:

:nodoc:
def self.full_message(attribute, message, base) # :nodoc:
  return message if attribute == :base
  base_class = base.class
  attribute = attribute.to_s
  if i18n_customize_full_message && base_class.respond_to?(:i18n_scope)
    attribute = attribute.remove(/\[\d+\]/)
    parts = attribute.split(".")
    attribute_name = parts.pop
    namespace = parts.join("/") unless parts.empty?
    attributes_scope = "#{base_class.i18n_scope}.errors.models"
    if namespace
      defaults = base_class.lookup_ancestors.map do |klass|
        [
          :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.attributes.#{attribute_name}.format",
          :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.format",
        ]
      end
    else
      defaults = base_class.lookup_ancestors.map do |klass|
        [
          :"#{attributes_scope}.#{klass.model_name.i18n_key}.attributes.#{attribute_name}.format",
          :"#{attributes_scope}.#{klass.model_name.i18n_key}.format",
        ]
      end
    end
    defaults.flatten!
  else
    defaults = []
  end
  defaults << :"errors.format"
  defaults << "%{attribute} %{message}"
  attr_name = attribute.remove(/\.base\z/).tr(".", "_").humanize
  attr_name = base_class.human_attribute_name(attribute, {
    default: attr_name,
    base: base,
  })
  I18n.t(defaults.shift,
    default:  defaults,
    attribute: attr_name,
    message:   message)
end

def self.generate_message(attribute, type, base, options) # :nodoc:

:nodoc:
def self.generate_message(attribute, type, base, options) # :nodoc:
  type = options.delete(:message) if options[:message].is_a?(Symbol)
  value = (attribute != :base ? base.read_attribute_for_validation(attribute) : nil)
  options = {
    model: base.model_name.human,
    attribute: base.class.human_attribute_name(attribute, { base: base }),
    value: value,
    object: base
  }.merge!(options)
  if base.class.respond_to?(:i18n_scope)
    i18n_scope = base.class.i18n_scope.to_s
    attribute = attribute.to_s.remove(/\[\d+\]/)
    defaults = base.class.lookup_ancestors.flat_map do |klass|
      [ :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
        :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
    end
    defaults << :"#{i18n_scope}.errors.messages.#{type}"
    catch(:exception) do
      translation = I18n.translate(defaults.first, **options.merge(default: defaults.drop(1), throw: true))
      return translation unless translation.nil?
    end unless options[:message]
  else
    defaults = []
  end
  defaults << :"errors.attributes.#{attribute}.#{type}"
  defaults << :"errors.messages.#{type}"
  key = defaults.shift
  defaults = options.delete(:message) if options[:message]
  options[:default] = defaults
  I18n.translate(key, **options)
end

def ==(other) # :nodoc:

:nodoc:
def ==(other) # :nodoc:
  other.is_a?(self.class) && attributes_for_hash == other.attributes_for_hash
end

def attributes_for_hash

def attributes_for_hash
  [@base, @attribute, @raw_type, @options.except(*CALLBACKS_OPTIONS)]
end

def details

# => { error: :too_short, count: 5 }
error.details
error = ActiveModel::Error.new(person, :name, :too_short, count: 5)

Returns the error details.
def details
  { error: raw_type }.merge(options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS))
end

def full_message

# => "Name is too short (minimum is 5 characters)"
error.full_message
error = ActiveModel::Error.new(person, :name, :too_short, count: 5)

Returns the full error message.
def full_message
  self.class.full_message(attribute, message, @base)
end

def hash # :nodoc:

:nodoc:
def hash # :nodoc:
  attributes_for_hash.hash
end

def initialize(base, attribute, type = :invalid, **options)

def initialize(base, attribute, type = :invalid, **options)
  @base = base
  @attribute = attribute
  @raw_type = type
  @type = type || :invalid
  @options = options
end

def initialize_dup(other) # :nodoc:

:nodoc:
def initialize_dup(other) # :nodoc:
  @attribute = @attribute.dup
  @raw_type = @raw_type.dup
  @type = @type.dup
  @options = @options.deep_dup
end

def inspect # :nodoc:

:nodoc:
def inspect # :nodoc:
  "#<#{self.class.name} attribute=#{@attribute}, type=#{@type}, options=#{@options.inspect}>"
end

def match?(attribute, type = nil, **options)

Omitted params are not checked for a match.

See if error matches provided +attribute+, +type+, and +options+.
def match?(attribute, type = nil, **options)
  if @attribute != attribute || (type && @type != type)
    return false
  end
  options.each do |key, value|
    if @options[key] != value
      return false
    end
  end
  true
end

def message

# => "is too short (minimum is 5 characters)"
error.message
error = ActiveModel::Error.new(person, :name, :too_short, count: 5)

Returns the error message.
def message
  case raw_type
  when Symbol
    self.class.generate_message(attribute, raw_type, @base, options.except(*CALLBACKS_OPTIONS))
  else
    raw_type
  end
end

def strict_match?(attribute, type, **options)

strict match.
All params must be equal to Error's own attributes to be considered a

See if error matches provided +attribute+, +type+, and +options+ exactly.
def strict_match?(attribute, type, **options)
  return false unless match?(attribute, type)
  options == @options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS)
end