Class: ActiveModel::Error

Inherits:
Object show all
Defined in:
activemodel/lib/active_model/error.rb

Overview

Active Model Error

Represents one single error

Direct Known Subclasses

NestedError

Constant Summary collapse

CALLBACKS_OPTIONS =
[:if, :unless, :on, :allow_nil, :allow_blank, :strict]
MESSAGE_OPTIONS =
[:message]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(base, attribute, type = :invalid, **options) ⇒ Error

Returns a new instance of Error.


98
99
100
101
102
103
104
# File 'activemodel/lib/active_model/error.rb', line 98

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

Instance Attribute Details

#attributeObject (readonly)

The attribute of base which the error belongs to


116
117
118
# File 'activemodel/lib/active_model/error.rb', line 116

def attribute
  @attribute
end

#baseObject (readonly)

The object which the error belongs to


114
115
116
# File 'activemodel/lib/active_model/error.rb', line 114

def base
  @base
end

#optionsObject (readonly)

The options provided when calling `errors#add`


122
123
124
# File 'activemodel/lib/active_model/error.rb', line 122

def options
  @options
end

#raw_typeObject (readonly)

The raw value provided as the second parameter when calling `errors#add`


120
121
122
# File 'activemodel/lib/active_model/error.rb', line 120

def raw_type
  @raw_type
end

#typeObject (readonly)

The type of error, defaults to `:invalid` unless specified


118
119
120
# File 'activemodel/lib/active_model/error.rb', line 118

def type
  @type
end

Class Method Details

.full_message(attribute, message, base_class) ⇒ Object

:nodoc:


15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'activemodel/lib/active_model/error.rb', line 15

def self.full_message(attribute, message, base_class) # :nodoc:
  return message if attribute == :base
  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.tr(".", "_").humanize
  attr_name = base_class.human_attribute_name(attribute, default: attr_name)

  I18n.t(defaults.shift,
    default:  defaults,
    attribute: attr_name,
    message:   message)
end

.generate_message(attribute, type, base, options) ⇒ Object

:nodoc:


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'activemodel/lib/active_model/error.rb', line 59

def self.generate_message(attribute, type, base, options) # :nodoc:
  type = options.delete(:message) if options[:message].is_a?(Symbol)
  value = (attribute != :base ? base.send(:read_attribute_for_validation, attribute) : nil)

  options = {
    model: base.model_name.human,
    attribute: base.class.human_attribute_name(attribute),
    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

Instance Method Details

#==(other) ⇒ Object Also known as: eql?


162
163
164
# File 'activemodel/lib/active_model/error.rb', line 162

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

#detailObject


133
134
135
# File 'activemodel/lib/active_model/error.rb', line 133

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

#full_messageObject


137
138
139
# File 'activemodel/lib/active_model/error.rb', line 137

def full_message
  self.class.full_message(attribute, message, @base.class)
end

#hashObject


167
168
169
# File 'activemodel/lib/active_model/error.rb', line 167

def hash
  attributes_for_hash.hash
end

#initialize_dup(other) ⇒ Object


106
107
108
109
110
111
# File 'activemodel/lib/active_model/error.rb', line 106

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

#inspectObject

:nodoc:


171
172
173
# File 'activemodel/lib/active_model/error.rb', line 171

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

#match?(attribute, type = nil, **options) ⇒ Boolean

See if error matches provided attribute, type and options.

Returns:

  • (Boolean)

142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'activemodel/lib/active_model/error.rb', line 142

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

#messageObject


124
125
126
127
128
129
130
131
# File 'activemodel/lib/active_model/error.rb', line 124

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

#strict_match?(attribute, type, **options) ⇒ Boolean

Returns:

  • (Boolean)

156
157
158
159
160
# File 'activemodel/lib/active_model/error.rb', line 156

def strict_match?(attribute, type, **options)
  return false unless match?(attribute, type)

  options == @options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS)
end