module Sequel::Plugins::ValidationClassMethods::ClassMethods

Attributes

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.

Public Instance Methods

freeze() click to toggle source

Freeze validation metadata when freezing model class.

Calls superclass method
   # 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
has_validations?() click to toggle source

Returns true if validations are defined.

   # File lib/sequel/plugins/validation_class_methods.rb
74 def has_validations?
75   !validations.empty?
76 end
skip_superclass_validations() click to toggle source

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
skip_superclass_validations?() click to toggle source

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
validate(o) click to toggle source

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
validates(&block) click to toggle source

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(*atts) click to toggle source

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(*atts) click to toggle source

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
validates_each(*atts, &block) click to toggle source

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, which Sequel 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 instance_execed) 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     proc do |o,a,v|
199       next if i && !validation_if_proc(o, i)
200       next if an && Array(v).all?(&:nil?)
201       next if ab && Array(v).all?(&blank_meth)
202       next if am && Array(a).all?{|x| !o.values.has_key?(x)}
203       block.call(o,a,v)
204     end
205   else
206     block
207   end
208   tag = opts[:tag]
209   atts.each do |a| 
210     a_vals = Sequel.synchronize{validations[a] ||= []}
211     if tag && (old = a_vals.find{|x| x[0] == tag})
212       old[1] = blk
213     else
214       a_vals << [tag, blk]
215     end
216   end
217 end
validates_format_of(*atts) click to toggle source

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
225 def validates_format_of(*atts)
226   opts = {
227     :message => 'is invalid',
228     :tag => :format,
229   }.merge!(extract_options!(atts))
230   
231   unless opts[:with].is_a?(Regexp)
232     raise ArgumentError, "A regular expression must be supplied as the :with option of the options hash"
233   end
234   
235   reflect_validation(:format, opts, atts)
236   atts << opts
237   validates_each(*atts) do |o, a, v|
238     o.errors.add(a, opts[:message]) unless v.to_s =~ opts[:with]
239   end
240 end
validates_inclusion_of(*atts) click to toggle source

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
329 def validates_inclusion_of(*atts)
330   opts = extract_options!(atts)
331   n = opts[:in]
332   unless n && (n.respond_to?(:cover?) || n.respond_to?(:include?))
333     raise ArgumentError, "The :in parameter is required, and must respond to cover? or include?"
334   end
335   opts[:message] ||= "is not in range or set: #{n.inspect}"
336   reflect_validation(:inclusion, opts, atts)
337   atts << opts
338   validates_each(*atts) do |o, a, v|
339     o.errors.add(a, opts[:message]) unless n.public_send(n.respond_to?(:cover?) ? :cover? : :include?, v)
340   end
341 end
validates_length_of(*atts) click to toggle source

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
255 def validates_length_of(*atts)
256   opts = {
257     :nil_message  => 'is not present',
258     :too_long     => 'is too long',
259     :too_short    => 'is too short',
260     :wrong_length => 'is the wrong length'
261   }.merge!(extract_options!(atts))
262   
263   opts[:tag] ||= ([:length] + [:maximum, :minimum, :is, :within].reject{|x| !opts.include?(x)}).join('-').to_sym
264   reflect_validation(:length, opts, atts)
265   atts << opts
266   validates_each(*atts) do |o, a, v|
267     if m = opts[:maximum]
268       o.errors.add(a, opts[:message] || (v ? opts[:too_long] : opts[:nil_message])) unless v && v.size <= m
269     end
270     if m = opts[:minimum]
271       o.errors.add(a, opts[:message] || opts[:too_short]) unless v && v.size >= m
272     end
273     if i = opts[:is]
274       o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && v.size == i
275     end
276     if w = opts[:within]
277       o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && w.public_send(w.respond_to?(:cover?) ? :cover? : :include?, v.size)
278     end
279   end
280 end
validates_numericality_of(*atts) click to toggle source

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
287 def validates_numericality_of(*atts)
288   opts = {
289     :message => 'is not a number',
290     :tag => :numericality,
291   }.merge!(extract_options!(atts))
292   reflect_validation(:numericality, opts, atts)
293   atts << opts
294   validates_each(*atts) do |o, a, v|
295     begin
296       if opts[:only_integer]
297         Kernel.Integer(v.to_s)
298       else
299         Kernel.Float(v.to_s)
300       end
301     rescue
302       o.errors.add(a, opts[:message])
303     end
304   end
305 end
validates_presence_of(*atts) click to toggle source

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
312 def validates_presence_of(*atts)
313   opts = {
314     :message => 'is not present',
315     :tag => :presence,
316   }.merge!(extract_options!(atts))
317   reflect_validation(:presence, opts, atts)
318   atts << opts
319   validates_each(*atts) do |o, a, v|
320     o.errors.add(a, opts[:message]) if db.send(:blank_object?, v) && v != false
321   end
322 end
validates_schema_type(*atts) click to toggle source

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
350 def validates_schema_type(*atts)
351   opts = {
352     :tag => :schema_type,
353   }.merge!(extract_options!(atts))
354   reflect_validation(:schema_type, opts, atts)
355   atts << opts
356   validates_each(*atts) do |o, a, v|
357     next if v.nil? || (klass = o.send(:schema_type_class, a)).nil?
358     if klass.is_a?(Array) ? !klass.any?{|kls| v.is_a?(kls)} : !v.is_a?(klass)
359       message = opts[:message] || "is not a valid #{Array(klass).join(" or ").downcase}"
360       o.errors.add(a, message)
361     end
362   end
363 end
validates_uniqueness_of(*atts) click to toggle source

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
381 def validates_uniqueness_of(*atts)
382   opts = {
383     :message => 'is already taken',
384     :tag => :uniqueness,
385   }.merge!(extract_options!(atts))
386     
387   reflect_validation(:uniqueness, opts, atts)
388   atts << opts
389   validates_each(*atts) do |o, a, v|
390     error_field = a
391     a = Array(a)
392     v = Array(v)
393     next if v.empty? || !v.all?
394     ds = o.class.where(a.zip(v))
395     num_dups = ds.count
396     allow = if num_dups == 0
397       # No unique value in the database
398       true
399     elsif num_dups > 1
400       # Multiple "unique" values in the database!!
401       # Someone didn't add a unique index
402       false
403     elsif o.new?
404       # New record, but unique value already exists in the database
405       false
406     elsif ds.first === o
407       # Unique value exists in database, but for the same record, so the update won't cause a duplicate record
408       true
409     else
410       false
411     end
412     o.errors.add(error_field, opts[:message]) unless allow
413   end
414 end

Private Instance Methods

extract_options!(array) click to toggle source

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
421 def extract_options!(array)
422   array.last.is_a?(Hash) ? array.pop : OPTS
423 end
reflect_validation(type, opts, atts) click to toggle source

Add the validation reflection to the class's validations.

    # File lib/sequel/plugins/validation_class_methods.rb
426 def reflect_validation(type, opts, atts)
427   atts.each do |att|
428     (validation_reflections[att] ||= []) << [type, opts]
429   end
430 end
validation_if_proc(o, i) click to toggle source

Handle the :if option for validations

    # File lib/sequel/plugins/validation_class_methods.rb
433 def validation_if_proc(o, i)
434   case i
435   when Symbol
436     o.get_column_value(i)
437   when Proc
438     o.instance_exec(&i)
439   else
440     raise(::Sequel::Error, "invalid value for :if validation option")
441   end
442 end