mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
d6cbb27e7b
Having a huge array to whitelist options is not the proper way to handle this case. This means that the ActiveModel::Errors object should know about the options given in *all* validators and break the extensibility added by the validators itself. If the intent is to whitelist options before sending them to I18n, each validator should clean its respective options instead of throwing the responsibility to the Errors object.
This reverts commit bc1c8d58ec
.
98 lines
5.3 KiB
Ruby
98 lines
5.3 KiB
Ruby
module ActiveModel
|
|
module Validations
|
|
class LengthValidator < EachValidator
|
|
MESSAGES = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }.freeze
|
|
CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze
|
|
|
|
DEFAULT_TOKENIZER = lambda { |value| value.split(//) }
|
|
|
|
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.begin, range.end
|
|
options[:maximum] -= 1 if range.exclude_end?
|
|
end
|
|
|
|
super(options.reverse_merge(:tokenizer => DEFAULT_TOKENIZER))
|
|
end
|
|
|
|
def check_validity!
|
|
keys = CHECKS.keys & options.keys
|
|
|
|
if keys.empty?
|
|
raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
|
|
end
|
|
|
|
keys.each do |key|
|
|
value = options[key]
|
|
|
|
unless value.is_a?(Integer) && value >= 0
|
|
raise ArgumentError, ":#{key} must be a nonnegative Integer"
|
|
end
|
|
end
|
|
end
|
|
|
|
def validate_each(record, attribute, value)
|
|
value = options[:tokenizer].call(value) if value.kind_of?(String)
|
|
|
|
CHECKS.each do |key, validity_check|
|
|
next unless check_value = options[key]
|
|
custom_message = options[:message] || options[MESSAGES[key]]
|
|
|
|
valid_value = if key == :maximum
|
|
value.nil? || value.size.send(validity_check, check_value)
|
|
else
|
|
value && value.size.send(validity_check, check_value)
|
|
end
|
|
|
|
next if valid_value
|
|
record.errors.add(attribute, MESSAGES[key], :default => custom_message, :count => check_value)
|
|
end
|
|
end
|
|
end
|
|
|
|
module HelperMethods
|
|
|
|
# Validates that the specified attribute matches the length restrictions supplied. Only one option can be used at a time:
|
|
#
|
|
# class Person < ActiveRecord::Base
|
|
# validates_length_of :first_name, :maximum=>30
|
|
# validates_length_of :last_name, :maximum=>30, :message=>"less than 30 if you don't mind"
|
|
# validates_length_of :fax, :in => 7..32, :allow_nil => true
|
|
# validates_length_of :phone, :in => 7..32, :allow_blank => true
|
|
# validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
|
|
# validates_length_of :zip_code, :minimum => 5, :too_short => "please enter at least 5 characters"
|
|
# validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with 4 characters... don't play me."
|
|
# validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least 100 words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
|
|
# end
|
|
#
|
|
# Configuration options:
|
|
# * <tt>:minimum</tt> - The minimum size of the attribute.
|
|
# * <tt>:maximum</tt> - The maximum size of the attribute.
|
|
# * <tt>:is</tt> - The exact size of the attribute.
|
|
# * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute.
|
|
# * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
|
|
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
|
|
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
|
|
# * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %{count} characters)").
|
|
# * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %{count} characters)").
|
|
# * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be %{count} characters)").
|
|
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
|
|
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
|
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
|
# method, proc or string should return or evaluate to a true or false value.
|
|
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
# method, proc or string should return or evaluate to a true or false value.
|
|
# * <tt>:tokenizer</tt> - Specifies how to split up the attribute string. (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to
|
|
# count words as in above example.)
|
|
# Defaults to <tt>lambda{ |value| value.split(//) }</tt> which counts individual characters.
|
|
def validates_length_of(*attr_names)
|
|
validates_with LengthValidator, _merge_attributes(attr_names)
|
|
end
|
|
|
|
alias_method :validates_size_of, :validates_length_of
|
|
end
|
|
end
|
|
end
|