Class: ActiveRecord::Validations::DatabaseConstraintsValidator

Inherits:
ActiveModel::EachValidator
  • Object
show all
Includes:
AdapterHelper
Defined in:
lib/active_record/validations/database_constraints.rb

Constant Summary collapse

VALID_CONSTRAINTS =
Set[:size, :not_null, :range]
SIZE_VALIDATORS_FOR_TYPE =
{
  characters: ActiveModel::Validations::LengthValidator,
  bytes: ActiveModel::Validations::BytesizeValidator,
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from AdapterHelper

#mysql_adapter?

Constructor Details

#initialize(options = {}) ⇒ DatabaseConstraintsValidator

Returns a new instance of DatabaseConstraintsValidator.



19
20
21
22
23
# File 'lib/active_record/validations/database_constraints.rb', line 19

def initialize(options = {})
  @constraints = Set.new(Array.wrap(options[:in]) + Array.wrap(options[:with]))
  @constraint_validators = {}
  super
end

Instance Attribute Details

#constraintsObject (readonly)

Returns the value of attribute constraints.



10
11
12
# File 'lib/active_record/validations/database_constraints.rb', line 10

def constraints
  @constraints
end

Instance Method Details

#attribute_validators(klass, attribute) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/active_record/validations/database_constraints.rb', line 62

def attribute_validators(klass, attribute)
  @constraint_validators[attribute] ||= begin
    column_definition = klass.columns_hash[attribute.to_s]

    unless column_definition
      raise ArgumentError.new("Model #{klass.name} does not have column #{attribute.to_s}!")
    end

    column = ActiveRecord::Validations::TypedColumn.new(column_definition)

    [
      not_null_validator(klass, column),
      size_validator(klass, column),
      range_validator(klass, column),
    ].compact
  end
end

#check_validity!Object

Raises:

  • (ArgumentError)


25
26
27
28
29
30
# File 'lib/active_record/validations/database_constraints.rb', line 25

def check_validity!
  invalid_constraints = constraints - VALID_CONSTRAINTS

  raise ArgumentError, "You have to specify what constraints to validate for." if constraints.empty?
  raise ArgumentError, "#{invalid_constraints.map(&:inspect).join(',')} is not a valid constraint." unless invalid_constraints.empty?
end

#not_null_validator(klass, column) ⇒ Object



32
33
34
35
36
37
# File 'lib/active_record/validations/database_constraints.rb', line 32

def not_null_validator(klass, column)
  return unless constraints.include?(:not_null)
  return if column.null

  ActiveModel::Validations::NotNullValidator.new(attributes: [column.name.to_sym], class: klass)
end

#range_validator(klass, column) ⇒ Object



52
53
54
55
56
57
58
59
60
# File 'lib/active_record/validations/database_constraints.rb', line 52

def range_validator(klass, column)
  return unless constraints.include?(:range)
  return unless mysql_adapter?(klass.connection)
  return unless column.number?

  args = { attributes: [column.name.to_sym], class: klass, allow_nil: true }
  args.merge!(ActiveRecord::DatabaseValidations::MySQL.column_range(column))
  ActiveModel::Validations::NumericalityValidator.new(args)
end

#size_validator(klass, column) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/active_record/validations/database_constraints.rb', line 39

def size_validator(klass, column)
  return unless constraints.include?(:size)
  return unless mysql_adapter?(klass.connection)
  return unless column.text? || column.binary?

  maximum, type, encoding = ActiveRecord::DatabaseValidations::MySQL.column_size_limit(column)
  validator_class = SIZE_VALIDATORS_FOR_TYPE[type]

  if validator_class && maximum
    validator_class.new(attributes: [column.name.to_sym], class: klass, maximum: maximum, encoding: encoding)
  end
end

#validate_each(record, attribute, _value) ⇒ Object



80
81
82
83
84
# File 'lib/active_record/validations/database_constraints.rb', line 80

def validate_each(record, attribute, _value)
  attribute_validators(record.class, attribute).each do |validator|
    validator.validate(record)
  end
end