Module | Sequel::Plugins::ValidationClassMethods::ClassMethods |
In: |
lib/sequel/plugins/validation_class_methods.rb
|
validations | [R] | A hash of associations 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 40 40: def has_validations? 41: !validations.empty? 42: end
Setup the validations hash in the subclass
# File lib/sequel/plugins/validation_class_methods.rb, line 45 45: def inherited(subclass) 46: super 47: subclass.class_eval do 48: @validation_mutex = Mutex.new 49: @validations = {} 50: end 51: end
Instructs the model to skip validations defined in superclasses
# File lib/sequel/plugins/validation_class_methods.rb, line 54 54: def skip_superclass_validations 55: @skip_superclass_validations = true 56: end
Instructs the model to skip validations defined in superclasses
# File lib/sequel/plugins/validation_class_methods.rb, line 59 59: def skip_superclass_validations? 60: defined?(@skip_superclass_validations) && @skip_superclass_validations 61: end
Validates the given instance.
# File lib/sequel/plugins/validation_class_methods.rb, line 83 83: def validate(o) 84: superclass.validate(o) if superclass.respond_to?(:validate) && !skip_superclass_validations? 85: validations.each do |att, procs| 86: v = case att 87: when Array 88: att.collect{|a| o.send(a)} 89: else 90: o.send(att) 91: end 92: procs.each {|tag, p| p.call(o, att, v)} 93: end 94: 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 78 78: def validates(&block) 79: Generator.new(self, &block) 80: 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 103 103: def validates_acceptance_of(*atts) 104: opts = { 105: :message => 'is not accepted', 106: :allow_nil => true, 107: :accept => '1', 108: :tag => :acceptance, 109: }.merge!(extract_options!(atts)) 110: atts << opts 111: validates_each(*atts) do |o, a, v| 112: o.errors.add(a, opts[:message]) unless v == opts[:accept] 113: end 114: 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 126 126: def validates_confirmation_of(*atts) 127: opts = { 128: :message => 'is not confirmed', 129: :tag => :confirmation, 130: }.merge!(extract_options!(atts)) 131: atts << opts 132: validates_each(*atts) do |o, a, v| 133: o.errors.add(a, opts[:message]) unless v == o.send("#{a}_confirmation""#{a}_confirmation") 134: end 135: 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 160 160: def validates_each(*atts, &block) 161: opts = extract_options!(atts) 162: blk = if (i = opts[:if]) || (am = opts[:allow_missing]) || (an = opts[:allow_nil]) || (ab = opts[:allow_blank]) 163: proc do |o,a,v| 164: next if i && !validation_if_proc(o, i) 165: next if an && Array(v).all?{|x| x.nil?} 166: next if ab && Array(v).all?{|x| x.blank?} 167: next if am && Array(a).all?{|x| !o.values.has_key?(x)} 168: block.call(o,a,v) 169: end 170: else 171: block 172: end 173: tag = opts[:tag] 174: atts.each do |a| 175: a_vals = @validation_mutex.synchronize{validations[a] ||= []} 176: if tag && (old = a_vals.find{|x| x[0] == tag}) 177: old[1] = blk 178: else 179: a_vals << [tag, blk] 180: end 181: end 182: 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 190 190: def validates_format_of(*atts) 191: opts = { 192: :message => 'is invalid', 193: :tag => :format, 194: }.merge!(extract_options!(atts)) 195: 196: unless opts[:with].is_a?(Regexp) 197: raise ArgumentError, "A regular expression must be supplied as the :with option of the options hash" 198: end 199: 200: atts << opts 201: validates_each(*atts) do |o, a, v| 202: o.errors.add(a, opts[:message]) unless v.to_s =~ opts[:with] 203: end 204: 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 316 316: def validates_inclusion_of(*atts) 317: opts = extract_options!(atts) 318: unless opts[:in] && opts[:in].respond_to?(:include?) 319: raise ArgumentError, "The :in parameter is required, and respond to include?" 320: end 321: opts[:message] ||= "is not in range or set: #{opts[:in].inspect}" 322: atts << opts 323: validates_each(*atts) do |o, a, v| 324: o.errors.add(a, opts[:message]) unless opts[:in].include?(v) 325: end 326: end
Validates the length of an attribute.
Possible Options:
# File lib/sequel/plugins/validation_class_methods.rb, line 218 218: def validates_length_of(*atts) 219: opts = { 220: :too_long => 'is too long', 221: :too_short => 'is too short', 222: :wrong_length => 'is the wrong length' 223: }.merge!(extract_options!(atts)) 224: 225: opts[:tag] ||= ([:length] + [:maximum, :minimum, :is, :within].reject{|x| !opts.include?(x)}).join('-').to_sym 226: atts << opts 227: validates_each(*atts) do |o, a, v| 228: if m = opts[:maximum] 229: o.errors.add(a, opts[:message] || opts[:too_long]) unless v && v.size <= m 230: end 231: if m = opts[:minimum] 232: o.errors.add(a, opts[:message] || opts[:too_short]) unless v && v.size >= m 233: end 234: if i = opts[:is] 235: o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && v.size == i 236: end 237: if w = opts[:within] 238: o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && w.include?(v.size) 239: end 240: end 241: end
Validates whether an attribute is not a string. This is generally useful in conjunction with raise_on_typecast_failure = false, where you are passing in string values for non-string attributes (such as numbers and dates). If typecasting fails (invalid number or date), the value of the attribute will be a string in an invalid format, and if typecasting succeeds, the value will not be a string.
Possible Options:
# File lib/sequel/plugins/validation_class_methods.rb, line 252 252: def validates_not_string(*atts) 253: opts = { 254: :tag => :not_string, 255: }.merge!(extract_options!(atts)) 256: atts << opts 257: validates_each(*atts) do |o, a, v| 258: if v.is_a?(String) 259: unless message = opts[:message] 260: message = if sch = o.db_schema[a] and typ = sch[:type] 261: "is not a valid #{typ}" 262: else 263: "is a string" 264: end 265: end 266: o.errors.add(a, message) 267: end 268: end 269: end
Validates whether an attribute is a number.
Possible Options:
# File lib/sequel/plugins/validation_class_methods.rb, line 276 276: def validates_numericality_of(*atts) 277: opts = { 278: :message => 'is not a number', 279: :tag => :numericality, 280: }.merge!(extract_options!(atts)) 281: atts << opts 282: validates_each(*atts) do |o, a, v| 283: begin 284: if opts[:only_integer] 285: Kernel.Integer(v.to_s) 286: else 287: Kernel.Float(v.to_s) 288: end 289: rescue 290: o.errors.add(a, opts[:message]) 291: end 292: end 293: 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 300 300: def validates_presence_of(*atts) 301: opts = { 302: :message => 'is not present', 303: :tag => :presence, 304: }.merge!(extract_options!(atts)) 305: atts << opts 306: validates_each(*atts) do |o, a, v| 307: o.errors.add(a, opts[:message]) if v.blank? && v != false 308: end 309: 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 344 344: def validates_uniqueness_of(*atts) 345: opts = { 346: :message => 'is already taken', 347: :tag => :uniqueness, 348: }.merge!(extract_options!(atts)) 349: 350: atts << opts 351: validates_each(*atts) do |o, a, v| 352: error_field = a 353: a = Array(a) 354: v = Array(v) 355: ds = o.class.filter(a.zip(v)) 356: num_dups = ds.count 357: allow = if num_dups == 0 358: # No unique value in the database 359: true 360: elsif num_dups > 1 361: # Multiple "unique" values in the database!! 362: # Someone didn't add a unique index 363: false 364: elsif o.new? 365: # New record, but unique value already exists in the database 366: false 367: elsif ds.first === o 368: # Unique value exists in database, but for the same record, so the update won't cause a duplicate record 369: true 370: else 371: false 372: end 373: o.errors.add(error_field, opts[:message]) unless allow 374: end 375: end