/usr/lib/ruby/vendor_ruby/active_model/validations.rb is in ruby-activemodel 2:4.2.6-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/hash/except'
module ActiveModel
# == Active \Model \Validations
#
# Provides a full validation framework to your objects.
#
# A minimal implementation could be:
#
# class Person
# include ActiveModel::Validations
#
# attr_accessor :first_name, :last_name
#
# validates_each :first_name, :last_name do |record, attr, value|
# record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
# end
# end
#
# Which provides you with the full standard validation stack that you
# know from Active Record:
#
# person = Person.new
# person.valid? # => true
# person.invalid? # => false
#
# person.first_name = 'zoolander'
# person.valid? # => false
# person.invalid? # => true
# person.errors.messages # => {first_name:["starts with z."]}
#
# Note that <tt>ActiveModel::Validations</tt> automatically adds an +errors+
# method to your instances initialized with a new <tt>ActiveModel::Errors</tt>
# object, so there is no need for you to do this manually.
module Validations
extend ActiveSupport::Concern
included do
extend ActiveModel::Naming
extend ActiveModel::Callbacks
extend ActiveModel::Translation
extend HelperMethods
include HelperMethods
attr_accessor :validation_context
private :validation_context=
define_callbacks :validate, scope: :name
class_attribute :_validators, instance_writer: false
self._validators = Hash.new { |h,k| h[k] = [] }
end
module ClassMethods
# Validates each attribute against a block.
#
# class Person
# include ActiveModel::Validations
#
# attr_accessor :first_name, :last_name
#
# validates_each :first_name, :last_name, allow_blank: true do |record, attr, value|
# record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
# end
# end
#
# Options:
# * <tt>:on</tt> - Specifies the contexts where this validation is active.
# Runs in all validation contexts by default (nil). You can pass a symbol
# or an array of symbols. (e.g. <tt>on: :create</tt> or
# <tt>on: :custom_validation_context</tt> or
# <tt>on: [:create, :custom_validation_context]</tt>)
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
# * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
# * <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.
def validates_each(*attr_names, &block)
validates_with BlockValidator, _merge_attributes(attr_names), &block
end
VALID_OPTIONS_FOR_VALIDATE = [:on, :if, :unless, :prepend].freeze # :nodoc:
# Adds a validation method or block to the class. This is useful when
# overriding the +validate+ instance method becomes too unwieldy and
# you're looking for more descriptive declaration of your validations.
#
# This can be done with a symbol pointing to a method:
#
# class Comment
# include ActiveModel::Validations
#
# validate :must_be_friends
#
# def must_be_friends
# errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
# end
# end
#
# With a block which is passed with the current record to be validated:
#
# class Comment
# include ActiveModel::Validations
#
# validate do |comment|
# comment.must_be_friends
# end
#
# def must_be_friends
# errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
# end
# end
#
# Or with a block where self points to the current record to be validated:
#
# class Comment
# include ActiveModel::Validations
#
# validate do
# errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
# end
# end
#
# Note that the return value of validation methods is not relevant.
# It's not possible to halt the validate callback chain.
#
# Options:
# * <tt>:on</tt> - Specifies the contexts where this validation is active.
# Runs in all validation contexts by default (nil). You can pass a symbol
# or an array of symbols. (e.g. <tt>on: :create</tt> or
# <tt>on: :custom_validation_context</tt> or
# <tt>on: [:create, :custom_validation_context]</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.
def validate(*args, &block)
options = args.extract_options!
if args.all? { |arg| arg.is_a?(Symbol) }
options.each_key do |k|
unless VALID_OPTIONS_FOR_VALIDATE.include?(k)
raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{VALID_OPTIONS_FOR_VALIDATE.map(&:inspect).join(', ')}. Perhaps you meant to call `validates` instead of `validate`?")
end
end
end
if options.key?(:on)
options = options.dup
options[:if] = Array(options[:if])
options[:if].unshift ->(o) {
Array(options[:on]).include?(o.validation_context)
}
end
args << options
set_callback(:validate, *args, &block)
end
# List all validators that are being used to validate the model using
# +validates_with+ method.
#
# class Person
# include ActiveModel::Validations
#
# validates_with MyValidator
# validates_with OtherValidator, on: :create
# validates_with StrictValidator, strict: true
# end
#
# Person.validators
# # => [
# # #<MyValidator:0x007fbff403e808 @options={}>,
# # #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
# # #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
# # ]
def validators
_validators.values.flatten.uniq
end
# Clears all of the validators and validations.
#
# Note that this will clear anything that is being used to validate
# the model for both the +validates_with+ and +validate+ methods.
# It clears the validators that are created with an invocation of
# +validates_with+ and the callbacks that are set by an invocation
# of +validate+.
#
# class Person
# include ActiveModel::Validations
#
# validates_with MyValidator
# validates_with OtherValidator, on: :create
# validates_with StrictValidator, strict: true
# validate :cannot_be_robot
#
# def cannot_be_robot
# errors.add(:base, 'A person cannot be a robot') if person_is_robot
# end
# end
#
# Person.validators
# # => [
# # #<MyValidator:0x007fbff403e808 @options={}>,
# # #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
# # #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
# # ]
#
# If one runs <tt>Person.clear_validators!</tt> and then checks to see what
# validators this class has, you would obtain:
#
# Person.validators # => []
#
# Also, the callback set by <tt>validate :cannot_be_robot</tt> will be erased
# so that:
#
# Person._validate_callbacks.empty? # => true
#
def clear_validators!
reset_callbacks(:validate)
_validators.clear
end
# List all validators that are being used to validate a specific attribute.
#
# class Person
# include ActiveModel::Validations
#
# attr_accessor :name , :age
#
# validates_presence_of :name
# validates_inclusion_of :age, in: 0..99
# end
#
# Person.validators_on(:name)
# # => [
# # #<ActiveModel::Validations::PresenceValidator:0x007fe604914e60 @attributes=[:name], @options={}>,
# # ]
def validators_on(*attributes)
attributes.flat_map do |attribute|
_validators[attribute.to_sym]
end
end
# Returns +true+ if +attribute+ is an attribute method, +false+ otherwise.
#
# class Person
# include ActiveModel::Validations
#
# attr_accessor :name
# end
#
# User.attribute_method?(:name) # => true
# User.attribute_method?(:age) # => false
def attribute_method?(attribute)
method_defined?(attribute)
end
# Copy validators on inheritance.
def inherited(base) #:nodoc:
dup = _validators.dup
base._validators = dup.each { |k, v| dup[k] = v.dup }
super
end
end
# Clean the +Errors+ object if instance is duped.
def initialize_dup(other) #:nodoc:
@errors = nil
super
end
# Returns the +Errors+ object that holds all information about attribute
# error messages.
#
# class Person
# include ActiveModel::Validations
#
# attr_accessor :name
# validates_presence_of :name
# end
#
# person = Person.new
# person.valid? # => false
# person.errors # => #<ActiveModel::Errors:0x007fe603816640 @messages={name:["can't be blank"]}>
def errors
@errors ||= Errors.new(self)
end
# Runs all the specified validations and returns +true+ if no errors were
# added otherwise +false+.
#
# Aliased as validate.
#
# class Person
# include ActiveModel::Validations
#
# attr_accessor :name
# validates_presence_of :name
# end
#
# person = Person.new
# person.name = ''
# person.valid? # => false
# person.name = 'david'
# person.valid? # => true
#
# Context can optionally be supplied to define which callbacks to test
# against (the context is defined on the validations using <tt>:on</tt>).
#
# class Person
# include ActiveModel::Validations
#
# attr_accessor :name
# validates_presence_of :name, on: :new
# end
#
# person = Person.new
# person.valid? # => true
# person.valid?(:new) # => false
def valid?(context = nil)
current_context, self.validation_context = validation_context, context
errors.clear
run_validations!
ensure
self.validation_context = current_context
end
alias_method :validate, :valid?
# Performs the opposite of <tt>valid?</tt>. Returns +true+ if errors were
# added, +false+ otherwise.
#
# class Person
# include ActiveModel::Validations
#
# attr_accessor :name
# validates_presence_of :name
# end
#
# person = Person.new
# person.name = ''
# person.invalid? # => true
# person.name = 'david'
# person.invalid? # => false
#
# Context can optionally be supplied to define which callbacks to test
# against (the context is defined on the validations using <tt>:on</tt>).
#
# class Person
# include ActiveModel::Validations
#
# attr_accessor :name
# validates_presence_of :name, on: :new
# end
#
# person = Person.new
# person.invalid? # => false
# person.invalid?(:new) # => true
def invalid?(context = nil)
!valid?(context)
end
# Hook method defining how an attribute value should be retrieved. By default
# this is assumed to be an instance named after the attribute. Override this
# method in subclasses should you need to retrieve the value for a given
# attribute differently:
#
# class MyClass
# include ActiveModel::Validations
#
# def initialize(data = {})
# @data = data
# end
#
# def read_attribute_for_validation(key)
# @data[key]
# end
# end
alias :read_attribute_for_validation :send
protected
def run_validations! #:nodoc:
_run_validate_callbacks
errors.empty?
end
end
end
Dir[File.dirname(__FILE__) + "/validations/*.rb"].each { |file| require file }
|