module Sequel::Plugins::ValidationClassMethods::ClassMethods
Attributes
A hash of validation reflections for this model class. Keys are column symbols, values are an array of two element arrays, with the first element being the validation type symbol and the second being a hash of validation options.
A hash of validations for this model class. Keys are column symbols, values are arrays of validation procs.
Public Instance Methods
Freeze validation metadata when freezing model class.
# File lib/sequel/plugins/validation_class_methods.rb 41 def freeze 42 @validations.freeze.each_value(&:freeze) 43 @validation_reflections.freeze.each_value do |vs| 44 vs.freeze.each do |v| 45 v.freeze 46 v.last.freeze 47 end 48 end 49 50 super 51 end
Returns true if validations are defined.
# File lib/sequel/plugins/validation_class_methods.rb 74 def has_validations? 75 !validations.empty? 76 end
Instructs the model to skip validations defined in superclasses
# File lib/sequel/plugins/validation_class_methods.rb 81 def skip_superclass_validations 82 superclass.validations.each do |att, procs| 83 if @validations[att] 84 @validations[att] -= procs 85 end 86 end 87 @skip_superclass_validations = true 88 end
Instructs the model to skip validations defined in superclasses
# File lib/sequel/plugins/validation_class_methods.rb 91 def skip_superclass_validations? 92 @skip_superclass_validations 93 end
Validates the given instance.
# File lib/sequel/plugins/validation_class_methods.rb 116 def validate(o) 117 validations.each do |att, procs| 118 v = case att 119 when Array 120 att.map{|a| o.get_column_value(a)} 121 else 122 o.get_column_value(att) 123 end 124 procs.each {|tag, p| p.call(o, att, v)} 125 end 126 end
Defines validations by converting a longhand block into a series of shorthand definitions. For example:
class MyClass < Sequel::Model validates do length_of :name, minimum: 6 length_of :password, minimum: 8 end end
is equivalent to:
class MyClass < Sequel::Model validates_length_of :name, minimum: 6 validates_length_of :password, minimum: 8 end
# File lib/sequel/plugins/validation_class_methods.rb 111 def validates(&block) 112 Generator.new(self, &block) 113 end
Validates acceptance of an attribute. Just checks that the value is equal to the :accept option. This method is unique in that :allow_nil is assumed to be true instead of false.
Possible Options:
- :accept
-
The value required for the object to be valid (default: '1')
- :message
-
The message to use (default: 'is not accepted')
# File lib/sequel/plugins/validation_class_methods.rb 135 def validates_acceptance_of(*atts) 136 opts = { 137 :message => 'is not accepted', 138 :allow_nil => true, 139 :accept => '1', 140 :tag => :acceptance, 141 }.merge!(extract_options!(atts)) 142 reflect_validation(:acceptance, opts, atts) 143 atts << opts 144 validates_each(*atts) do |o, a, v| 145 o.errors.add(a, opts[:message]) unless v == opts[:accept] 146 end 147 end
Validates confirmation of an attribute. Checks that the object has a _confirmation value matching the current value. For example:
validates_confirmation_of :blah
Just makes sure that object.blah = object.blah_confirmation. Often used for passwords or email addresses on web forms.
Possible Options:
- :message
-
The message to use (default: 'is not confirmed')
# File lib/sequel/plugins/validation_class_methods.rb 159 def validates_confirmation_of(*atts) 160 opts = { 161 :message => 'is not confirmed', 162 :tag => :confirmation, 163 }.merge!(extract_options!(atts)) 164 reflect_validation(:confirmation, opts, atts) 165 atts << opts 166 validates_each(*atts) do |o, a, v| 167 o.errors.add(a, opts[:message]) unless v == o.get_column_value(:"#{a}_confirmation") 168 end 169 end
Adds a validation for each of the given attributes using the supplied block. The block must accept three arguments: instance, attribute and value, e.g.:
validates_each :name, :password do |object, attribute, value| object.errors.add(attribute, 'is not nice') unless value.nice? end
Possible Options:
- :allow_blank
-
Whether to skip the validation if the value is blank.
- :allow_missing
-
Whether to skip the validation if the attribute isn't a key in the values hash. This is different from allow_nil, because
Sequel
only sends the attributes in the values when doing an insert or update. If the attribute is not present,Sequel
doesn't specify it, so the database will use the table's default value. This is different from having an attribute in values with a value of nil, whichSequel
will send as NULL. If your database table has a non NULL default, this may be a good option to use. You don't want to use allow_nil, because if the attribute is in values but has a value nil,Sequel
will attempt to insert a NULL value into the database, instead of using the database's default. - :allow_nil
-
Whether to skip the validation if the value is nil.
- :if
-
A symbol (indicating an instance_method) or proc (which is used to define an instance method) skipping this validation if it returns nil or false.
- :tag
-
The tag to use for this validation.
# File lib/sequel/plugins/validation_class_methods.rb 194 def validates_each(*atts, &block) 195 opts = extract_options!(atts) 196 blank_meth = db.method(:blank_object?).to_proc 197 blk = if (i = opts[:if]) || (am = opts[:allow_missing]) || (an = opts[:allow_nil]) || (ab = opts[:allow_blank]) 198 if i.is_a?(Proc) 199 i = Plugins.def_sequel_method(self, "validation_class_methods_if", 0, &i) 200 end 201 202 proc do |o,a,v| 203 next if i && !validation_if_proc(o, i) 204 next if an && Array(v).all?(&:nil?) 205 next if ab && Array(v).all?(&blank_meth) 206 next if am && Array(a).all?{|x| !o.values.has_key?(x)} 207 block.call(o,a,v) 208 end 209 else 210 block 211 end 212 tag = opts[:tag] 213 atts.each do |a| 214 a_vals = Sequel.synchronize{validations[a] ||= []} 215 if tag && (old = a_vals.find{|x| x[0] == tag}) 216 old[1] = blk 217 else 218 a_vals << [tag, blk] 219 end 220 end 221 end
Validates the format of an attribute, checking the string representation of the value against the regular expression provided by the :with option.
Possible Options:
- :message
-
The message to use (default: 'is invalid')
- :with
-
The regular expression to validate the value with (required).
# File lib/sequel/plugins/validation_class_methods.rb 229 def validates_format_of(*atts) 230 opts = { 231 :message => 'is invalid', 232 :tag => :format, 233 }.merge!(extract_options!(atts)) 234 235 unless opts[:with].is_a?(Regexp) 236 raise ArgumentError, "A regular expression must be supplied as the :with option of the options hash" 237 end 238 239 reflect_validation(:format, opts, atts) 240 atts << opts 241 validates_each(*atts) do |o, a, v| 242 o.errors.add(a, opts[:message]) unless v.to_s =~ opts[:with] 243 end 244 end
Validates that an attribute is within a specified range or set of values.
Possible Options:
- :in
-
An array or range of values to check for validity (required)
- :message
-
The message to use (default: 'is not in range or set: <specified range>')
# File lib/sequel/plugins/validation_class_methods.rb 333 def validates_inclusion_of(*atts) 334 opts = extract_options!(atts) 335 n = opts[:in] 336 unless n && (n.respond_to?(:cover?) || n.respond_to?(:include?)) 337 raise ArgumentError, "The :in parameter is required, and must respond to cover? or include?" 338 end 339 opts[:message] ||= "is not in range or set: #{n.inspect}" 340 reflect_validation(:inclusion, opts, atts) 341 atts << opts 342 validates_each(*atts) do |o, a, v| 343 o.errors.add(a, opts[:message]) unless n.public_send(n.respond_to?(:cover?) ? :cover? : :include?, v) 344 end 345 end
Validates the length of an attribute.
Possible Options:
- :is
-
The exact size required for the value to be valid (no default)
- :maximum
-
The maximum size allowed for the value (no default)
- :message
-
The message to use (no default, overrides :nil_message, :too_long, :too_short, and :wrong_length options if present)
- :minimum
-
The minimum size allowed for the value (no default)
- :nil_message
-
The message to use use if :maximum option is used and the value is nil (default: 'is not present')
- :too_long
-
The message to use use if it the value is too long (default: 'is too long')
- :too_short
-
The message to use use if it the value is too short (default: 'is too short')
- :within
-
The array/range that must include the size of the value for it to be valid (no default)
- :wrong_length
-
The message to use use if it the value is not valid (default: 'is the wrong length')
# File lib/sequel/plugins/validation_class_methods.rb 259 def validates_length_of(*atts) 260 opts = { 261 :nil_message => 'is not present', 262 :too_long => 'is too long', 263 :too_short => 'is too short', 264 :wrong_length => 'is the wrong length' 265 }.merge!(extract_options!(atts)) 266 267 opts[:tag] ||= ([:length] + [:maximum, :minimum, :is, :within].reject{|x| !opts.include?(x)}).join('-').to_sym 268 reflect_validation(:length, opts, atts) 269 atts << opts 270 validates_each(*atts) do |o, a, v| 271 if m = opts[:maximum] 272 o.errors.add(a, opts[:message] || (v ? opts[:too_long] : opts[:nil_message])) unless v && v.size <= m 273 end 274 if m = opts[:minimum] 275 o.errors.add(a, opts[:message] || opts[:too_short]) unless v && v.size >= m 276 end 277 if i = opts[:is] 278 o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && v.size == i 279 end 280 if w = opts[:within] 281 o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && w.public_send(w.respond_to?(:cover?) ? :cover? : :include?, v.size) 282 end 283 end 284 end
Validates whether an attribute is a number.
Possible Options:
- :message
-
The message to use (default: 'is not a number')
- :only_integer
-
Whether only integers are valid values (default: false)
# File lib/sequel/plugins/validation_class_methods.rb 291 def validates_numericality_of(*atts) 292 opts = { 293 :message => 'is not a number', 294 :tag => :numericality, 295 }.merge!(extract_options!(atts)) 296 reflect_validation(:numericality, opts, atts) 297 atts << opts 298 validates_each(*atts) do |o, a, v| 299 begin 300 if opts[:only_integer] 301 Kernel.Integer(v.to_s) 302 else 303 Kernel.Float(v.to_s) 304 end 305 rescue 306 o.errors.add(a, opts[:message]) 307 end 308 end 309 end
Validates the presence of an attribute. Requires the value not be blank, with false considered present instead of absent.
Possible Options:
- :message
-
The message to use (default: 'is not present')
# File lib/sequel/plugins/validation_class_methods.rb 316 def validates_presence_of(*atts) 317 opts = { 318 :message => 'is not present', 319 :tag => :presence, 320 }.merge!(extract_options!(atts)) 321 reflect_validation(:presence, opts, atts) 322 atts << opts 323 validates_each(*atts) do |o, a, v| 324 o.errors.add(a, opts[:message]) if db.send(:blank_object?, v) && v != false 325 end 326 end
Validates whether an attribute has the correct ruby type for the associated database type. This is generally useful in conjunction with raise_on_typecast_failure = false, to handle typecasting errors at validation time instead of at setter time.
Possible Options:
- :message
-
The message to use (default: 'is not a valid (integer|datetime|etc.)')
# File lib/sequel/plugins/validation_class_methods.rb 354 def validates_schema_type(*atts) 355 opts = { 356 :tag => :schema_type, 357 }.merge!(extract_options!(atts)) 358 reflect_validation(:schema_type, opts, atts) 359 atts << opts 360 validates_each(*atts) do |o, a, v| 361 next if v.nil? || (klass = o.send(:schema_type_class, a)).nil? 362 if klass.is_a?(Array) ? !klass.any?{|kls| v.is_a?(kls)} : !v.is_a?(klass) 363 message = opts[:message] || "is not a valid #{Array(klass).join(" or ").downcase}" 364 o.errors.add(a, message) 365 end 366 end 367 end
Validates only if the fields in the model (specified by atts) are unique in the database. Pass an array of fields instead of multiple fields to specify that the combination of fields must be unique, instead of that each field should have a unique value.
This means that the code:
validates_uniqueness_of([:column1, :column2])
validates the grouping of column1 and column2 while
validates_uniqueness_of(:column1, :column2)
validates them separately.
You should also add a unique index in the database, as this suffers from a fairly obvious race condition.
Possible Options:
- :message
-
The message to use (default: 'is already taken')
# File lib/sequel/plugins/validation_class_methods.rb 385 def validates_uniqueness_of(*atts) 386 opts = { 387 :message => 'is already taken', 388 :tag => :uniqueness, 389 }.merge!(extract_options!(atts)) 390 391 reflect_validation(:uniqueness, opts, atts) 392 atts << opts 393 validates_each(*atts) do |o, a, v| 394 error_field = a 395 a = Array(a) 396 v = Array(v) 397 next if v.empty? || !v.all? 398 ds = o.class.where(a.zip(v)) 399 num_dups = ds.count 400 allow = if num_dups == 0 401 # No unique value in the database 402 true 403 elsif num_dups > 1 404 # Multiple "unique" values in the database!! 405 # Someone didn't add a unique index 406 false 407 elsif o.new? 408 # New record, but unique value already exists in the database 409 false 410 elsif ds.first === o 411 # Unique value exists in database, but for the same record, so the update won't cause a duplicate record 412 true 413 else 414 false 415 end 416 o.errors.add(error_field, opts[:message]) unless allow 417 end 418 end
Private Instance Methods
Removes and returns the last member of the array if it is a hash. Otherwise, an empty hash is returned This method is useful when writing methods that take an options hash as the last parameter.
# File lib/sequel/plugins/validation_class_methods.rb 425 def extract_options!(array) 426 array.last.is_a?(Hash) ? array.pop : OPTS 427 end
Add the validation reflection to the class's validations.
# File lib/sequel/plugins/validation_class_methods.rb 430 def reflect_validation(type, opts, atts) 431 atts.each do |att| 432 (validation_reflections[att] ||= []) << [type, opts] 433 end 434 end
Handle the :if option for validations
# File lib/sequel/plugins/validation_class_methods.rb 437 def validation_if_proc(o, i) 438 case i 439 when Symbol 440 o.get_column_value(i) 441 else 442 raise(::Sequel::Error, "invalid value for :if validation option") 443 end 444 end