Class: ActiveModel::Validations::LengthValidator

Inherits:
EachValidator show all
Defined in:
lib/active_model/validations/length.rb

Overview

:nodoc:

Constant Summary collapse

MESSAGES =
{ is: :wrong_length, minimum: :too_short, maximum: :too_long }.freeze
CHECKS =
{ is: :==, minimum: :>=, maximum: :<= }.freeze
RESERVED_OPTIONS =
[:minimum, :maximum, :within, :is, :tokenizer, :too_short, :too_long]

Instance Attribute Summary

Attributes inherited from EachValidator

#attributes

Attributes inherited from ActiveModel::Validator

#options

Instance Method Summary collapse

Methods inherited from EachValidator

#validate

Methods inherited from ActiveModel::Validator

kind, #kind, #validate

Constructor Details

#initialize(options) ⇒ LengthValidator

Returns a new instance of LengthValidator.



11
12
13
14
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
# File 'lib/active_model/validations/length.rb', line 11

def initialize(options)
  if range = (options.delete(:in) || options.delete(:within))
    raise ArgumentError, ":in and :within must be a Range" unless range.is_a?(Range)
    options[:minimum], options[:maximum] = range.min, range.max
  end

  if options[:allow_blank] == false && options[:minimum].nil? && options[:is].nil?
    options[:minimum] = 1
  end

  if options[:tokenizer]
    ActiveSupport::Deprecation.warn(<<-EOS.strip_heredoc)
      The `:tokenizer` option is deprecated, and will be removed in Rails 5.1.
      You can achieve the same functionality by defining an instance method
      with the value that you want to validate the length of. For example,

          validates_length_of :essay, minimum: 100,
            tokenizer: ->(str) { str.scan(/\w+/) }

      should be written as

          validates_length_of :words_in_essay, minimum: 100

          private

          def words_in_essay
            essay.scan(/\w+/)
          end
    EOS
  end

  super
end

Instance Method Details

#check_validity!Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/active_model/validations/length.rb', line 45

def check_validity!
  keys = CHECKS.keys & options.keys

  if keys.empty?
    raise ArgumentError, 'Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option.'
  end

  keys.each do |key|
    value = options[key]

    unless (value.is_a?(Integer) && value >= 0) || value == Float::INFINITY
      raise ArgumentError, ":#{key} must be a nonnegative Integer or Infinity"
    end
  end
end

#validate_each(record, attribute, value) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/active_model/validations/length.rb', line 61

def validate_each(record, attribute, value)
  value = tokenize(record, value)
  value_length = value.respond_to?(:length) ? value.length : value.to_s.length
  errors_options = options.except(*RESERVED_OPTIONS)

  CHECKS.each do |key, validity_check|
    next unless check_value = options[key]

    if !value.nil? || skip_nil_check?(key)
      next if value_length.send(validity_check, check_value)
    end

    errors_options[:count] = check_value

    default_message = options[MESSAGES[key]]
    errors_options[:message] ||= default_message if default_message

    record.errors.add(attribute, MESSAGES[key], errors_options)
  end
end