Class: ActiveModel::Hints

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/active_model/hints.rb

Overview

Introspects declared validators and builds proactive hint messages (before valid? fails).

Conditional options (:if, :unless, :on) are not evaluated; hints reflect static rules. For format validators, prefer a custom message: or per-attribute I18n keys.

Constant Summary collapse

MESSAGES_FOR_OPTIONS =
%w[
  within in is minimum maximum greater_than greater_than_or_equal_to
  equal_to less_than less_than_or_equal_to odd even only_integer
].freeze
VALIDATORS_WITHOUT_MAIN_KEYS =
%w[exclusion format inclusion length numericality].freeze
RANGE_OPTIONS =
%w[within in].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(base) ⇒ Hints

Returns a new instance of Hints.



22
23
24
25
26
27
28
# File 'lib/active_model/hints.rb', line 22

def initialize(base)
  @base = base
  @messages = {}
  attribute_names_for_hints.each do |attribute|
    @messages[attribute] = hints_for(attribute)
  end
end

Instance Attribute Details

#messagesObject (readonly)

Returns the value of attribute messages.



20
21
22
# File 'lib/active_model/hints.rb', line 20

def messages
  @messages
end

Instance Method Details

#[](attribute) ⇒ Object



68
69
70
# File 'lib/active_model/hints.rb', line 68

def [](attribute)
  get(attribute.to_sym) || set(attribute.to_sym, [])
end

#[]=(attribute, hint) ⇒ Object



72
73
74
# File 'lib/active_model/hints.rb', line 72

def []=(attribute, hint)
  self[attribute] << hint
end

#add(attribute, message = :invalid, options = {}) ⇒ Object



119
120
121
122
123
124
125
126
# File 'lib/active_model/hints.rb', line 119

def add(attribute, message = :invalid, options = {})
  message = normalize_message(attribute, message, options)
  if options[:strict]
    raise ActiveModel::StrictValidationFailed, full_message(attribute, message)
  end

  self[attribute] << message
end

#add_on_blank(attributes, options = {}) ⇒ Object



136
137
138
139
140
141
# File 'lib/active_model/hints.rb', line 136

def add_on_blank(attributes, options = {})
  Array(attributes).each do |attribute|
    value = @base.send(:read_attribute_for_validation, attribute)
    add(attribute, :blank, options) if value.blank?
  end
end

#add_on_empty(attributes, options = {}) ⇒ Object



128
129
130
131
132
133
134
# File 'lib/active_model/hints.rb', line 128

def add_on_empty(attributes, options = {})
  Array(attributes).each do |attribute|
    value = @base.send(:read_attribute_for_validation, attribute)
    is_empty = value.respond_to?(:empty?) ? value.empty? : false
    add(attribute, :empty, options) if value.nil? || is_empty
  end
end

#added?(attribute, message = :invalid, options = {}) ⇒ Boolean

Returns:

  • (Boolean)


143
144
145
146
# File 'lib/active_model/hints.rb', line 143

def added?(attribute, message = :invalid, options = {})
  message = normalize_message(attribute, message, options)
  self[attribute].include?(message)
end

#as_json(_options = nil) ⇒ Object



111
112
113
# File 'lib/active_model/hints.rb', line 111

def as_json(_options = nil)
  to_hash
end

#clearObject



47
48
49
# File 'lib/active_model/hints.rb', line 47

def clear
  messages.clear
end

#countObject



98
99
100
# File 'lib/active_model/hints.rb', line 98

def count
  to_a.size
end

#delete(key) ⇒ Object



64
65
66
# File 'lib/active_model/hints.rb', line 64

def delete(key)
  messages.delete(key)
end

#eachObject



76
77
78
79
80
# File 'lib/active_model/hints.rb', line 76

def each
  messages.each_key do |attribute|
    self[attribute].each { |hint| yield attribute, hint }
  end
end

#empty?Boolean Also known as: blank?

Returns:

  • (Boolean)


102
103
104
# File 'lib/active_model/hints.rb', line 102

def empty?
  messages.values.all?(&:empty?)
end

#full_message(attribute, message) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/active_model/hints.rb', line 152

def full_message(attribute, message)
  return message if attribute == :base

  attr_name = attribute.to_s.tr(".", "_").humanize
  attr_name = @base.class.human_attribute_name(attribute, default: attr_name, base: @base)

  format_defaults = i18n_format_defaults
  format_key = format_defaults.shift

  I18n.t(
    format_key,
    default: format_defaults,
    attribute: attr_name,
    message: message
  )
end

#full_messagesObject



148
149
150
# File 'lib/active_model/hints.rb', line 148

def full_messages
  map { |attribute, message| full_message(attribute, message) }
end

#full_messages_for(attribute) ⇒ Object



39
40
41
# File 'lib/active_model/hints.rb', line 39

def full_messages_for(attribute)
  hints_for(attribute).map { |message| full_message(attribute, message) }
end

#generate_message(attribute, type, options = {}) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/active_model/hints.rb', line 169

def generate_message(attribute, type, options = {})
  options = options.dup
  type = options.delete(:message) if options[:message].is_a?(Symbol)
  value = (attribute != :base ? @base.read_attribute_for_validation(attribute) : nil)

  interpolation = {
    model: @base.model_name.human,
    attribute: @base.class.human_attribute_name(attribute, base: @base),
    value: value,
    object: @base,
    count: options[:count],
    minimum: options[:minimum],
    maximum: options[:maximum]
  }.compact

  defaults = i18n_defaults(attribute, type, options)
  key = defaults.shift

  I18n.translate(key, **interpolation.merge(default: defaults))
end

#get(key) ⇒ Object



56
57
58
# File 'lib/active_model/hints.rb', line 56

def get(key)
  messages[key]
end

#hints_for(attribute) ⇒ Object



30
31
32
33
34
35
36
37
# File 'lib/active_model/hints.rb', line 30

def hints_for(attribute)
  attribute = attribute.to_sym
  result = []
  @base.class.validators_on(attribute).each do |validator|
    result.concat(messages_for_validator(attribute, validator))
  end
  result
end

#include?(attribute) ⇒ Boolean Also known as: has_key?

Returns:

  • (Boolean)


51
52
53
# File 'lib/active_model/hints.rb', line 51

def include?(attribute)
  (value = messages[attribute.to_sym]) && value.any?
end

#initialize_dup(other) ⇒ Object



43
44
45
# File 'lib/active_model/hints.rb', line 43

def initialize_dup(other)
  @messages = other.messages.transform_values(&:dup)
end

#keysObject



90
91
92
# File 'lib/active_model/hints.rb', line 90

def keys
  messages.keys
end

#set(key, value) ⇒ Object



60
61
62
# File 'lib/active_model/hints.rb', line 60

def set(key, value)
  messages[key] = value
end

#sizeObject



82
83
84
# File 'lib/active_model/hints.rb', line 82

def size
  values.flatten.size
end

#to_aObject



94
95
96
# File 'lib/active_model/hints.rb', line 94

def to_a
  full_messages
end

#to_hashObject



115
116
117
# File 'lib/active_model/hints.rb', line 115

def to_hash
  messages.dup
end

#to_xml(options = {}) ⇒ Object



107
108
109
# File 'lib/active_model/hints.rb', line 107

def to_xml(options = {})
  to_a.to_xml(options.reverse_merge(root: "hints", skip_types: true))
end

#valuesObject



86
87
88
# File 'lib/active_model/hints.rb', line 86

def values
  messages.values
end