| 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 57
57: def has_validations?
58: !validations.empty?
59: end
Setup the validations and validation_reflections hash in the subclass.
# File lib/sequel/plugins/validation_class_methods.rb, line 62
62: def inherited(subclass)
63: super
64: vr = @validation_reflections
65: subclass.class_eval do
66: @validation_mutex = Mutex.new
67: @validations = {}
68: h = {}
69: vr.each{|k,v| h[k] = v.dup}
70: @validation_reflections = h
71: end
72: end
Instructs the model to skip validations defined in superclasses
# File lib/sequel/plugins/validation_class_methods.rb, line 75
75: def skip_superclass_validations
76: @skip_superclass_validations = true
77: end
Instructs the model to skip validations defined in superclasses
# File lib/sequel/plugins/validation_class_methods.rb, line 80
80: def skip_superclass_validations?
81: defined?(@skip_superclass_validations) && @skip_superclass_validations
82: end
Validates the given instance.
# File lib/sequel/plugins/validation_class_methods.rb, line 104
104: def validate(o)
105: superclass.validate(o) if superclass.respond_to?(:validate) && !skip_superclass_validations?
106: validations.each do |att, procs|
107: v = case att
108: when Array
109: att.collect{|a| o.send(a)}
110: else
111: o.send(att)
112: end
113: procs.each {|tag, p| p.call(o, att, v)}
114: end
115: 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 99
99: def validates(&block)
100: Generator.new(self, &block)
101: 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 124
124: def validates_acceptance_of(*atts)
125: opts = {
126: :message => 'is not accepted',
127: :allow_nil => true,
128: :accept => '1',
129: :tag => :acceptance,
130: }.merge!(extract_options!(atts))
131: reflect_validation(:acceptance, opts, atts)
132: atts << opts
133: validates_each(*atts) do |o, a, v|
134: o.errors.add(a, opts[:message]) unless v == opts[:accept]
135: end
136: 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 148
148: def validates_confirmation_of(*atts)
149: opts = {
150: :message => 'is not confirmed',
151: :tag => :confirmation,
152: }.merge!(extract_options!(atts))
153: reflect_validation(:confirmation, opts, atts)
154: atts << opts
155: validates_each(*atts) do |o, a, v|
156: o.errors.add(a, opts[:message]) unless v == o.send("#{a}_confirmation""#{a}_confirmation")
157: end
158: 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 183
183: def validates_each(*atts, &block)
184: opts = extract_options!(atts)
185: blk = if (i = opts[:if]) || (am = opts[:allow_missing]) || (an = opts[:allow_nil]) || (ab = opts[:allow_blank])
186: proc do |o,a,v|
187: next if i && !validation_if_proc(o, i)
188: next if an && Array(v).all?{|x| x.nil?}
189: next if ab && Array(v).all?{|x| x.blank?}
190: next if am && Array(a).all?{|x| !o.values.has_key?(x)}
191: block.call(o,a,v)
192: end
193: else
194: block
195: end
196: tag = opts[:tag]
197: atts.each do |a|
198: a_vals = @validation_mutex.synchronize{validations[a] ||= []}
199: if tag && (old = a_vals.find{|x| x[0] == tag})
200: old[1] = blk
201: else
202: a_vals << [tag, blk]
203: end
204: end
205: 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 213
213: def validates_format_of(*atts)
214: opts = {
215: :message => 'is invalid',
216: :tag => :format,
217: }.merge!(extract_options!(atts))
218:
219: unless opts[:with].is_a?(Regexp)
220: raise ArgumentError, "A regular expression must be supplied as the :with option of the options hash"
221: end
222:
223: reflect_validation(:format, opts, atts)
224: atts << opts
225: validates_each(*atts) do |o, a, v|
226: o.errors.add(a, opts[:message]) unless v.to_s =~ opts[:with]
227: end
228: 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 346
346: def validates_inclusion_of(*atts)
347: opts = extract_options!(atts)
348: n = opts[:in]
349: unless n && (n.respond_to?(:cover?) || n.respond_to?(:include?))
350: raise ArgumentError, "The :in parameter is required, and must respond to cover? or include?"
351: end
352: opts[:message] ||= "is not in range or set: #{n.inspect}"
353: reflect_validation(:inclusion, opts, atts)
354: atts << opts
355: validates_each(*atts) do |o, a, v|
356: o.errors.add(a, opts[:message]) unless n.send(n.respond_to?(:cover?) ? :cover? : :include?, v)
357: end
358: end
Validates the length of an attribute.
Possible Options:
# File lib/sequel/plugins/validation_class_methods.rb, line 243
243: def validates_length_of(*atts)
244: opts = {
245: :nil_message => 'is not present',
246: :too_long => 'is too long',
247: :too_short => 'is too short',
248: :wrong_length => 'is the wrong length'
249: }.merge!(extract_options!(atts))
250:
251: opts[:tag] ||= ([:length] + [:maximum, :minimum, :is, :within].reject{|x| !opts.include?(x)}).join('-').to_sym
252: reflect_validation(:length, opts, atts)
253: atts << opts
254: validates_each(*atts) do |o, a, v|
255: if m = opts[:maximum]
256: o.errors.add(a, opts[:message] || (v ? opts[:too_long] : opts[:nil_message])) unless v && v.size <= m
257: end
258: if m = opts[:minimum]
259: o.errors.add(a, opts[:message] || opts[:too_short]) unless v && v.size >= m
260: end
261: if i = opts[:is]
262: o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && v.size == i
263: end
264: if w = opts[:within]
265: o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && w.send(w.respond_to?(:cover?) ? :cover? : :include?, v.size)
266: end
267: end
268: 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 279
279: def validates_not_string(*atts)
280: opts = {
281: :tag => :not_string,
282: }.merge!(extract_options!(atts))
283: reflect_validation(:not_string, opts, atts)
284: atts << opts
285: validates_each(*atts) do |o, a, v|
286: if v.is_a?(String)
287: unless message = opts[:message]
288: message = if sch = o.db_schema[a] and typ = sch[:type]
289: "is not a valid #{typ}"
290: else
291: "is a string"
292: end
293: end
294: o.errors.add(a, message)
295: end
296: end
297: end
Validates whether an attribute is a number.
Possible Options:
# File lib/sequel/plugins/validation_class_methods.rb, line 304
304: def validates_numericality_of(*atts)
305: opts = {
306: :message => 'is not a number',
307: :tag => :numericality,
308: }.merge!(extract_options!(atts))
309: reflect_validation(:numericality, opts, atts)
310: atts << opts
311: validates_each(*atts) do |o, a, v|
312: begin
313: if opts[:only_integer]
314: Kernel.Integer(v.to_s)
315: else
316: Kernel.Float(v.to_s)
317: end
318: rescue
319: o.errors.add(a, opts[:message])
320: end
321: end
322: 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 329
329: def validates_presence_of(*atts)
330: opts = {
331: :message => 'is not present',
332: :tag => :presence,
333: }.merge!(extract_options!(atts))
334: reflect_validation(:presence, opts, atts)
335: atts << opts
336: validates_each(*atts) do |o, a, v|
337: o.errors.add(a, opts[:message]) if v.blank? && v != false
338: end
339: 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 376
376: def validates_uniqueness_of(*atts)
377: opts = {
378: :message => 'is already taken',
379: :tag => :uniqueness,
380: }.merge!(extract_options!(atts))
381:
382: reflect_validation(:uniqueness, opts, atts)
383: atts << opts
384: validates_each(*atts) do |o, a, v|
385: error_field = a
386: a = Array(a)
387: v = Array(v)
388: ds = o.class.filter(a.zip(v))
389: num_dups = ds.count
390: allow = if num_dups == 0
391: # No unique value in the database
392: true
393: elsif num_dups > 1
394: # Multiple "unique" values in the database!!
395: # Someone didn't add a unique index
396: false
397: elsif o.new?
398: # New record, but unique value already exists in the database
399: false
400: elsif ds.first === o
401: # Unique value exists in database, but for the same record, so the update won't cause a duplicate record
402: true
403: else
404: false
405: end
406: o.errors.add(error_field, opts[:message]) unless allow
407: end
408: end