Module: Validation::ClassMethods

Defined in:
lib/sequel_model/validations.rb

Overview

Validation class methods.

Instance Method Summary collapse

Instance Method Details

#has_validations?Boolean

Returns true if validations are defined.

Returns:

  • (Boolean)


107
108
109
# File 'lib/sequel_model/validations.rb', line 107

def has_validations?
  !validations.empty?
end

#skip_superclass_validationsObject

Instructs the model to skip validations defined in superclasses



112
113
114
# File 'lib/sequel_model/validations.rb', line 112

def skip_superclass_validations
  @skip_superclass_validations = true
end

#validate(o) ⇒ Object

Validates the given instance.



138
139
140
141
142
143
144
145
146
# File 'lib/sequel_model/validations.rb', line 138

def validate(o)
  if superclass.respond_to?(:validate) && !@skip_superclass_validations
    superclass.validate(o)
  end
  validations.each do |att, procs|
    v = o.send(att)
    procs.each {|p| p[o, att, v]}
  end
end

#validates(&block) ⇒ Object

Defines validations by converting a longhand block into a series of shorthand definitions. For example:

class MyClass
  include Validation
  validates do
    length_of :name, :minimum => 6
    length_of :password, :minimum => 8
  end
end

is equivalent to:

class MyClass
  include Validation
  validates_length_of :name, :minimum => 6
  validates_length_of :password, :minimum => 8
end


133
134
135
# File 'lib/sequel_model/validations.rb', line 133

def validates(&block)
  Generator.new(self, &block)
end

#validates_acceptance_of(*atts) ⇒ Object

Validates acceptance of an attribute.



149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/sequel_model/validations.rb', line 149

def validates_acceptance_of(*atts)
  opts = {
    :message => 'is not accepted',
    :allow_nil => true,
    :accept => '1'
  }.merge!(atts.extract_options!)
  
  validates_each(*atts) do |o, a, v|
    next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank])
    o.errors[a] << opts[:message] unless v == opts[:accept]
  end
end

#validates_confirmation_of(*atts) ⇒ Object

Validates confirmation of an attribute.



163
164
165
166
167
168
169
170
171
172
173
# File 'lib/sequel_model/validations.rb', line 163

def validates_confirmation_of(*atts)
  opts = {
    :message => 'is not confirmed',
  }.merge!(atts.extract_options!)
  
  validates_each(*atts) do |o, a, v|
    next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank])
    c = o.send(:"#{a}_confirmation")
    o.errors[a] << opts[:message] unless v == c
  end
end

#validates_each(*atts, &block) ⇒ Object

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[attribute] << 'is not nice' unless value.nice?
end


182
183
184
# File 'lib/sequel_model/validations.rb', line 182

def validates_each(*atts, &block)
  atts.each {|a| validations[a] << block}
end

#validates_format_of(*atts) ⇒ Object

Validates the format of an attribute.



187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/sequel_model/validations.rb', line 187

def validates_format_of(*atts)
  opts = {
    :message => 'is invalid',
  }.merge!(atts.extract_options!)
  
  unless opts[:with].is_a?(Regexp)
    raise ArgumentError, "A regular expression must be supplied as the :with option of the options hash"
  end
  
  validates_each(*atts) do |o, a, v|
    next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank])
    o.errors[a] << opts[:message] unless v.to_s =~ opts[:with]
  end
end

#validates_length_of(*atts) ⇒ Object

Validates the length of an attribute.



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/sequel_model/validations.rb', line 203

def validates_length_of(*atts)
  opts = {
    :too_long     => 'is too long',
    :too_short    => 'is too short',
    :wrong_length => 'is the wrong length'
  }.merge!(atts.extract_options!)
  
  validates_each(*atts) do |o, a, v|
    next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank])
    if m = opts[:maximum]
      o.errors[a] << (opts[:message] || opts[:too_long]) unless v && v.size <= m
    end
    if m = opts[:minimum]
      o.errors[a] << (opts[:message] || opts[:too_short]) unless v && v.size >= m
    end
    if i = opts[:is]
      o.errors[a] << (opts[:message] || opts[:wrong_length]) unless v && v.size == i
    end
    if w = opts[:within]
      o.errors[a] << (opts[:message] || opts[:wrong_length]) unless v && w.include?(v.size)
    end
  end
end

#validates_numericality_of(*atts) ⇒ Object

Validates whether an attribute is a number.



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/sequel_model/validations.rb', line 228

def validates_numericality_of(*atts)
  opts = {
    :message => 'is not a number',
  }.merge!(atts.extract_options!)
  
  validates_each(*atts) do |o, a, v|
    next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank])
    begin
      if opts[:only_integer]
        Kernel.Integer(v.to_s)
      else
        Kernel.Float(v.to_s)
      end
    rescue
      o.errors[a] << opts[:message]
    end
  end
end

#validates_presence_of(*atts) ⇒ Object

Validates the presence of an attribute.



248
249
250
251
252
253
254
255
256
# File 'lib/sequel_model/validations.rb', line 248

def validates_presence_of(*atts)
  opts = {
    :message => 'is not present',
  }.merge!(atts.extract_options!)
  
  validates_each(*atts) do |o, a, v|
    o.errors[a] << opts[:message] unless v && !v.blank?
  end
end

#validates_uniqueness_of(*atts) ⇒ Object

Validates only if the fields in the model (specified by atts) are unique in the database. You should also add a unique index in the database, as this suffers from a fairly obvious race condition.



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/sequel_model/validations.rb', line 261

def validates_uniqueness_of(*atts)
  opts = {
    :message => 'is already taken',
  }.merge!(atts.extract_options!)

  validates_each(*atts) do |o, a, v|
    next if v.blank? 
    num_dups = o.class.filter(a => v).count
    allow = if num_dups == 0
      # No unique value in the database
      true
    elsif num_dups > 1
      # Multiple "unique" values in the database!!
      # Someone didn't add a unique index
      false
    elsif o.new?
      # New record, but unique value already exists in the database
      false
    elsif o.class[a => v].pk == o.pk
      # Unique value exists in database, but for the same record, so the update won't cause a duplicate record
      true
    else
      false
    end
    o.errors[a] << opts[:message] unless allow
  end
end

#validationsObject

Returns the validations hash for the class.



290
291
292
# File 'lib/sequel_model/validations.rb', line 290

def validations
  @validations ||= Hash.new {|h, k| h[k] = []}
end