module Sequel::Plugins::ValidationClassMethods::ClassMethods

  1. lib/sequel/plugins/validation_class_methods.rb

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()

Freeze validation metadata when freezing model class.

[show source]
   # 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?()

Returns true if validations are defined.

[show source]
   # File lib/sequel/plugins/validation_class_methods.rb
74 def has_validations?
75   !validations.empty?
76 end
skip_superclass_validations()

Instructs the model to skip validations defined in superclasses

[show source]
   # 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?()

Instructs the model to skip validations defined in superclasses

[show source]
   # File lib/sequel/plugins/validation_class_methods.rb
91 def skip_superclass_validations?
92   @skip_superclass_validations
93 end
validate(o)

Validates the given instance.

[show source]
    # 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)

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
[show source]
    # File lib/sequel/plugins/validation_class_methods.rb
111 def validates(&block)
112   Generator.new(self, &block)
113 end
validates_acceptance_of(*atts)

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')

[show source]
    # 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)

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')

[show source]
    # 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)

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.

[show source]
    # 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   i = opts[:if]
198   am = opts[:allow_missing]
199   an = opts[:allow_nil]
200   ab = opts[:allow_blank]
201   blk = if i || am || an || ab
202     if i.is_a?(Proc)
203       i = Plugins.def_sequel_method(self, "validation_class_methods_if", 0, &i)
204     end
205 
206     proc do |o,a,v|
207       next if i && !validation_if_proc(o, i)
208       next if an && Array(v).all?(&:nil?)
209       next if ab && Array(v).all?(&blank_meth)
210       next if am && Array(a).all?{|x| !o.values.has_key?(x)}
211       block.call(o,a,v)
212     end
213   else
214     block
215   end
216   tag = opts[:tag]
217   atts.each do |a| 
218     a_vals = Sequel.synchronize{validations[a] ||= []}
219     if tag && (old = a_vals.find{|x| x[0] == tag})
220       old[1] = blk
221     else
222       a_vals << [tag, blk]
223     end
224   end
225 end
validates_format_of(*atts)

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).

[show source]
    # File lib/sequel/plugins/validation_class_methods.rb
233 def validates_format_of(*atts)
234   opts = {
235     :message => 'is invalid',
236     :tag => :format,
237   }.merge!(extract_options!(atts))
238   
239   unless opts[:with].is_a?(Regexp)
240     raise ArgumentError, "A regular expression must be supplied as the :with option of the options hash"
241   end
242   
243   reflect_validation(:format, opts, atts)
244   atts << opts
245   validates_each(*atts) do |o, a, v|
246     o.errors.add(a, opts[:message]) unless v.to_s =~ opts[:with]
247   end
248 end
validates_inclusion_of(*atts)

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>')

[show source]
    # File lib/sequel/plugins/validation_class_methods.rb
337 def validates_inclusion_of(*atts)
338   opts = extract_options!(atts)
339   n = opts[:in]
340   unless n && (n.respond_to?(:cover?) || n.respond_to?(:include?))
341     raise ArgumentError, "The :in parameter is required, and must respond to cover? or include?"
342   end
343   opts[:message] ||= "is not in range or set: #{n.inspect}"
344   reflect_validation(:inclusion, opts, atts)
345   atts << opts
346   validates_each(*atts) do |o, a, v|
347     o.errors.add(a, opts[:message]) unless n.public_send(n.respond_to?(:cover?) ? :cover? : :include?, v)
348   end
349 end
validates_length_of(*atts)

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')

[show source]
    # File lib/sequel/plugins/validation_class_methods.rb
263 def validates_length_of(*atts)
264   opts = {
265     :nil_message  => 'is not present',
266     :too_long     => 'is too long',
267     :too_short    => 'is too short',
268     :wrong_length => 'is the wrong length'
269   }.merge!(extract_options!(atts))
270   
271   opts[:tag] ||= ([:length] + [:maximum, :minimum, :is, :within].reject{|x| !opts.include?(x)}).join('-').to_sym
272   reflect_validation(:length, opts, atts)
273   atts << opts
274   validates_each(*atts) do |o, a, v|
275     if m = opts[:maximum]
276       o.errors.add(a, opts[:message] || (v ? opts[:too_long] : opts[:nil_message])) unless v && v.size <= m
277     end
278     if m = opts[:minimum]
279       o.errors.add(a, opts[:message] || opts[:too_short]) unless v && v.size >= m
280     end
281     if i = opts[:is]
282       o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && v.size == i
283     end
284     if w = opts[:within]
285       o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && w.public_send(w.respond_to?(:cover?) ? :cover? : :include?, v.size)
286     end
287   end
288 end
validates_numericality_of(*atts)

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)

[show source]
    # File lib/sequel/plugins/validation_class_methods.rb
295 def validates_numericality_of(*atts)
296   opts = {
297     :message => 'is not a number',
298     :tag => :numericality,
299   }.merge!(extract_options!(atts))
300   reflect_validation(:numericality, opts, atts)
301   atts << opts
302   validates_each(*atts) do |o, a, v|
303     begin
304       if opts[:only_integer]
305         Kernel.Integer(v.to_s)
306       else
307         Kernel.Float(v.to_s)
308       end
309     rescue
310       o.errors.add(a, opts[:message])
311     end
312   end
313 end
validates_presence_of(*atts)

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')

[show source]
    # File lib/sequel/plugins/validation_class_methods.rb
320 def validates_presence_of(*atts)
321   opts = {
322     :message => 'is not present',
323     :tag => :presence,
324   }.merge!(extract_options!(atts))
325   reflect_validation(:presence, opts, atts)
326   atts << opts
327   validates_each(*atts) do |o, a, v|
328     o.errors.add(a, opts[:message]) if db.send(:blank_object?, v) && v != false
329   end
330 end
validates_schema_type(*atts)

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.)')

[show source]
    # File lib/sequel/plugins/validation_class_methods.rb
358 def validates_schema_type(*atts)
359   opts = {
360     :tag => :schema_type,
361   }.merge!(extract_options!(atts))
362   reflect_validation(:schema_type, opts, atts)
363   atts << opts
364   validates_each(*atts) do |o, a, v|
365     next if v.nil? || (klass = o.send(:schema_type_class, a)).nil?
366     if klass.is_a?(Array) ? !klass.any?{|kls| v.is_a?(kls)} : !v.is_a?(klass)
367       message = opts[:message] || "is not a valid #{Array(klass).join(" or ").downcase}"
368       o.errors.add(a, message)
369     end
370   end
371 end
validates_uniqueness_of(*atts)

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')

[show source]
    # File lib/sequel/plugins/validation_class_methods.rb
389 def validates_uniqueness_of(*atts)
390   opts = {
391     :message => 'is already taken',
392     :tag => :uniqueness,
393   }.merge!(extract_options!(atts))
394     
395   reflect_validation(:uniqueness, opts, atts)
396   atts << opts
397   validates_each(*atts) do |o, a, v|
398     error_field = a
399     a = Array(a)
400     v = Array(v)
401     next if v.empty? || !v.all?
402     ds = o.class.where(a.zip(v))
403     num_dups = ds.count
404     allow = if num_dups == 0
405       # No unique value in the database
406       true
407     elsif num_dups > 1
408       # Multiple "unique" values in the database!!
409       # Someone didn't add a unique index
410       false
411     elsif o.new?
412       # New record, but unique value already exists in the database
413       false
414     elsif ds.first === o
415       # Unique value exists in database, but for the same record, so the update won't cause a duplicate record
416       true
417     else
418       false
419     end
420     o.errors.add(error_field, opts[:message]) unless allow
421   end
422 end