module BetterValidations::Validator

Public Class Methods

bind_validator(nested_name) click to toggle source

Calls a validates_with method to save information about the validating object to the validator and run validations.

# File lib/better_validations/validator.rb, line 26
def self.bind_validator(nested_name)
  validates_with BetterValidations::NestedValidator,
                 attributes: [nested_name]
end
define_attributes_setter(nested_name) click to toggle source

Defines an _attributes setter in order to set a value by _attributes key instead of an original name.

# File lib/better_validations/validator.rb, line 42
def self.define_attributes_setter(nested_name)
  setter_name = "#{nested_name}_attributes="
  define_method(setter_name) { |value| set_value(nested_name, value) }
end
define_nested_object_setter(nested_name, validator_class) click to toggle source

Overriders the setter for nested object in order to create the instance of validator instead of hash/params/ActiveRecord.

# File lib/better_validations/validator.rb, line 33
def self.define_nested_object_setter(nested_name, validator_class)
  define_method("#{nested_name}=".to_sym) do |value|
    validator = init_nested_object_validator(validator_class, value)
    instance_variable_set("@#{nested_name}".to_sym, validator)
  end
end
new(attributes = {}) click to toggle source

Attributes - Hash, ActionController::Parameters or ActiveRecord::Base

# File lib/better_validations/validator.rb, line 75
def initialize(attributes = {})
  assign_attributes(attributes)
end
structure() click to toggle source

Returns a structure of validators such as: { field: { kind: true }, nested: { field: { kind: true } } } where “kind” is a validator kind such as “presence”.

# File lib/better_validations/validator.rb, line 50
def self.structure
  validators_by_field_name.reduce({}) do |structure, (field, validator)|
    validations = (structure[field] || {}).merge(validator_hash(validator))
    structure.merge(field => validations)
  end
end
validate_nested(nested_name, validator_class) click to toggle source

A helper method to validate nested object/list represented by other validator.

Example of usage in a User model for validating nested PersonalInfo: validate_nested :personal_info, PersonalInfoValidator

# File lib/better_validations/validator.rb, line 18
def self.validate_nested(nested_name, validator_class)
  bind_validator(nested_name)
  define_nested_object_setter(nested_name, validator_class)
  define_attributes_setter(nested_name)
end
validator_hash(validator) click to toggle source

Returns a hash such as: { kind: true } where “kind” is a validator kind such as “presence”.

# File lib/better_validations/validator.rb, line 69
def self.validator_hash(validator)
  kind = validator.kind
  kind == :nested ? validator.validator_class.structure : { kind => true }
end
validators_by_field_name() click to toggle source

Returns an array:

[:field_one, validator], [:field_two, validator]

fields can duplicate if have multiple validators.

# File lib/better_validations/validator.rb, line 60
def self.validators_by_field_name
  validators.map do |validator|
    validator.attributes.map { |attribute| [attribute, validator] }
  end.flatten(1)
end

Public Instance Methods

assign_attributes(attributes) click to toggle source
# File lib/better_validations/validator.rb, line 79
def assign_attributes(attributes)
  prepare_attributes(attributes).each { |key, value| set_value(key, value) }
end
attribute_names() click to toggle source
# File lib/better_validations/validator.rb, line 113
def attribute_names
  (self.class.validators.map(&:attributes).flatten + [:client_id, :id]).uniq
end
convert_active_record_to_attributes(object) click to toggle source
# File lib/better_validations/validator.rb, line 105
def convert_active_record_to_attributes(object)
  attribute_names.reduce({}) do |hash, name|
    next hash unless object.respond_to?(name)

    hash.merge(name => object.public_send(name))
  end
end
init_nested_object_validator(validator_class, value) click to toggle source
# File lib/better_validations/validator.rb, line 122
def init_nested_object_validator(validator_class, value)
  return nil if value.nil?

  # A value can be a single object or a list of objects
  if value.is_a?(Hash) || value.is_a?(ActionController::Parameters)
    validator_class.new(value)
  elsif value.is_a?(Enumerable)
    init_nested_object_validators_list(value, validator_class)
  elsif value.is_a?(BetterValidations::Validator)
    value
  else
    validator_class.new(value)
  end
end
init_nested_object_validators_list(list, validator_class) click to toggle source
# File lib/better_validations/validator.rb, line 137
def init_nested_object_validators_list(list, validator_class)
  list.map do |object|
    if object.is_a?(BetterValidations::Validator)
      object
    else
      validator_class.new(object)
    end
  end
end
merge(*validators) click to toggle source
# File lib/better_validations/validator.rb, line 83
def merge(*validators)
  BetterValidations::ValidatorsList.new(*([self] + validators))
end
prepare_attributes(attributes) click to toggle source
# File lib/better_validations/validator.rb, line 96
def prepare_attributes(attributes)
  if attributes.is_a? ActiveRecord::Base
    @validation_object = attributes
    attributes = convert_active_record_to_attributes(attributes)
  end

  attributes
end
read_attribute_for_validation(attr) click to toggle source
# File lib/better_validations/validator.rb, line 87
def read_attribute_for_validation(attr)
  # Default implementation is 'send(attr)', but it fails if set
  # an :blank error as a symbol to the nested object:
  #   errors.add(:'nested_name.nested_attribute', :blank)
  try(attr)
end
set_value(key, value) click to toggle source
# File lib/better_validations/validator.rb, line 117
def set_value(key, value)
  setter = "#{key}=".to_sym
  public_send(setter, value) if respond_to?(setter)
end