Module | Sequel::Plugins::ValidationClassMethods::ClassMethods |
In: |
lib/sequel/plugins/validation_class_methods.rb
|
validation_reflections | [R] | 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. |
validations | [R] | A hash of validations for this model class. Keys are column symbols, values are arrays of validation procs. |
Returns true if validations are defined.
# File lib/sequel/plugins/validation_class_methods.rb, line 61 61: def has_validations? 62: !validations.empty? 63: end
Instructs the model to skip validations defined in superclasses
# File lib/sequel/plugins/validation_class_methods.rb, line 68 68: def skip_superclass_validations 69: superclass.validations.each do |att, procs| 70: if ps = @validations[att] 71: @validations[att] -= procs 72: end 73: end 74: @skip_superclass_validations = true 75: end
Instructs the model to skip validations defined in superclasses
# File lib/sequel/plugins/validation_class_methods.rb, line 78 78: def skip_superclass_validations? 79: @skip_superclass_validations 80: end
Validates the given instance.
# File lib/sequel/plugins/validation_class_methods.rb, line 102 102: def validate(o) 103: validations.each do |att, procs| 104: v = case att 105: when Array 106: att.collect{|a| o.send(a)} 107: else 108: o.send(att) 109: end 110: procs.each {|tag, p| p.call(o, att, v)} 111: end 112: 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, line 97 97: def validates(&block) 98: Generator.new(self, &block) 99: 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:
# File lib/sequel/plugins/validation_class_methods.rb, line 121 121: def validates_acceptance_of(*atts) 122: opts = { 123: :message => 'is not accepted', 124: :allow_nil => true, 125: :accept => '1', 126: :tag => :acceptance, 127: }.merge!(extract_options!(atts)) 128: reflect_validation(:acceptance, opts, atts) 129: atts << opts 130: validates_each(*atts) do |o, a, v| 131: o.errors.add(a, opts[:message]) unless v == opts[:accept] 132: end 133: 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:
# File lib/sequel/plugins/validation_class_methods.rb, line 145 145: def validates_confirmation_of(*atts) 146: opts = { 147: :message => 'is not confirmed', 148: :tag => :confirmation, 149: }.merge!(extract_options!(atts)) 150: reflect_validation(:confirmation, opts, atts) 151: atts << opts 152: validates_each(*atts) do |o, a, v| 153: o.errors.add(a, opts[:message]) unless v == o.send("#{a}_confirmation""#{a}_confirmation") 154: end 155: 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:
# File lib/sequel/plugins/validation_class_methods.rb, line 180 180: def validates_each(*atts, &block) 181: opts = extract_options!(atts) 182: blk = if (i = opts[:if]) || (am = opts[:allow_missing]) || (an = opts[:allow_nil]) || (ab = opts[:allow_blank]) 183: proc do |o,a,v| 184: next if i && !validation_if_proc(o, i) 185: next if an && Array(v).all?{|x| x.nil?} 186: next if ab && Array(v).all?{|x| x.blank?} 187: next if am && Array(a).all?{|x| !o.values.has_key?(x)} 188: block.call(o,a,v) 189: end 190: else 191: block 192: end 193: tag = opts[:tag] 194: atts.each do |a| 195: a_vals = Sequel.synchronize{validations[a] ||= []} 196: if tag && (old = a_vals.find{|x| x[0] == tag}) 197: old[1] = blk 198: else 199: a_vals << [tag, blk] 200: end 201: end 202: 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:
# File lib/sequel/plugins/validation_class_methods.rb, line 210 210: def validates_format_of(*atts) 211: opts = { 212: :message => 'is invalid', 213: :tag => :format, 214: }.merge!(extract_options!(atts)) 215: 216: unless opts[:with].is_a?(Regexp) 217: raise ArgumentError, "A regular expression must be supplied as the :with option of the options hash" 218: end 219: 220: reflect_validation(:format, opts, atts) 221: atts << opts 222: validates_each(*atts) do |o, a, v| 223: o.errors.add(a, opts[:message]) unless v.to_s =~ opts[:with] 224: end 225: end
Validates that an attribute is within a specified range or set of values.
Possible Options:
# File lib/sequel/plugins/validation_class_methods.rb, line 314 314: def validates_inclusion_of(*atts) 315: opts = extract_options!(atts) 316: n = opts[:in] 317: unless n && (n.respond_to?(:cover?) || n.respond_to?(:include?)) 318: raise ArgumentError, "The :in parameter is required, and must respond to cover? or include?" 319: end 320: opts[:message] ||= "is not in range or set: #{n.inspect}" 321: reflect_validation(:inclusion, opts, atts) 322: atts << opts 323: validates_each(*atts) do |o, a, v| 324: o.errors.add(a, opts[:message]) unless n.send(n.respond_to?(:cover?) ? :cover? : :include?, v) 325: end 326: end
Validates the length of an attribute.
Possible Options:
# File lib/sequel/plugins/validation_class_methods.rb, line 240 240: def validates_length_of(*atts) 241: opts = { 242: :nil_message => 'is not present', 243: :too_long => 'is too long', 244: :too_short => 'is too short', 245: :wrong_length => 'is the wrong length' 246: }.merge!(extract_options!(atts)) 247: 248: opts[:tag] ||= ([:length] + [:maximum, :minimum, :is, :within].reject{|x| !opts.include?(x)}).join('-').to_sym 249: reflect_validation(:length, opts, atts) 250: atts << opts 251: validates_each(*atts) do |o, a, v| 252: if m = opts[:maximum] 253: o.errors.add(a, opts[:message] || (v ? opts[:too_long] : opts[:nil_message])) unless v && v.size <= m 254: end 255: if m = opts[:minimum] 256: o.errors.add(a, opts[:message] || opts[:too_short]) unless v && v.size >= m 257: end 258: if i = opts[:is] 259: o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && v.size == i 260: end 261: if w = opts[:within] 262: o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && w.send(w.respond_to?(:cover?) ? :cover? : :include?, v.size) 263: end 264: end 265: end
Validates whether an attribute is a number.
Possible Options:
# File lib/sequel/plugins/validation_class_methods.rb, line 272 272: def validates_numericality_of(*atts) 273: opts = { 274: :message => 'is not a number', 275: :tag => :numericality, 276: }.merge!(extract_options!(atts)) 277: reflect_validation(:numericality, opts, atts) 278: atts << opts 279: validates_each(*atts) do |o, a, v| 280: begin 281: if opts[:only_integer] 282: Kernel.Integer(v.to_s) 283: else 284: Kernel.Float(v.to_s) 285: end 286: rescue 287: o.errors.add(a, opts[:message]) 288: end 289: end 290: end
Validates the presence of an attribute. Requires the value not be blank, with false considered present instead of absent.
Possible Options:
# File lib/sequel/plugins/validation_class_methods.rb, line 297 297: def validates_presence_of(*atts) 298: opts = { 299: :message => 'is not present', 300: :tag => :presence, 301: }.merge!(extract_options!(atts)) 302: reflect_validation(:presence, opts, atts) 303: atts << opts 304: validates_each(*atts) do |o, a, v| 305: o.errors.add(a, opts[:message]) if v.blank? && v != false 306: end 307: 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:
# File lib/sequel/plugins/validation_class_methods.rb, line 335 335: def validates_schema_type(*atts) 336: opts = { 337: :tag => :schema_type, 338: }.merge!(extract_options!(atts)) 339: reflect_validation(:schema_type, opts, atts) 340: atts << opts 341: validates_each(*atts) do |o, a, v| 342: next if v.nil? || (klass = o.send(:schema_type_class, a)).nil? 343: if klass.is_a?(Array) ? !klass.any?{|kls| v.is_a?(kls)} : !v.is_a?(klass) 344: message = opts[:message] || "is not a valid #{Array(klass).join(" or ").downcase}" 345: o.errors.add(a, message) 346: end 347: end 348: 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:
# File lib/sequel/plugins/validation_class_methods.rb, line 366 366: def validates_uniqueness_of(*atts) 367: opts = { 368: :message => 'is already taken', 369: :tag => :uniqueness, 370: }.merge!(extract_options!(atts)) 371: 372: reflect_validation(:uniqueness, opts, atts) 373: atts << opts 374: validates_each(*atts) do |o, a, v| 375: error_field = a 376: a = Array(a) 377: v = Array(v) 378: next if v.empty? || !v.all? 379: ds = o.class.filter(a.zip(v)) 380: num_dups = ds.count 381: allow = if num_dups == 0 382: # No unique value in the database 383: true 384: elsif num_dups > 1 385: # Multiple "unique" values in the database!! 386: # Someone didn't add a unique index 387: false 388: elsif o.new? 389: # New record, but unique value already exists in the database 390: false 391: elsif ds.first === o 392: # Unique value exists in database, but for the same record, so the update won't cause a duplicate record 393: true 394: else 395: false 396: end 397: o.errors.add(error_field, opts[:message]) unless allow 398: end 399: end