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 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_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
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_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
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_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
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_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
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_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
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_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
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_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
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

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
425 def extract_options!(array)
426   array.last.is_a?(Hash) ? array.pop : OPTS
427 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
430 def reflect_validation(type, opts, atts)
431   atts.each do |att|
432     (validation_reflections[att] ||= []) << [type, opts]
433   end
434 end
validation_if_proc(o, i) click to toggle source

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