Skip to content

Sage/validation_profiler

Repository files navigation

ValidationProfiler

RSpec Maintainability Test Coverage Gem Version

Welcome to ValidationProfiler. This is a validation framework that allows you to seperate validation logic away from your objects and into validation profiles that can be re-used and changed without affecting your objects.

Installation

Add this line to your application's Gemfile:

gem 'validation_profiler'

And then execute:

$ bundle

Or install it yourself as:

$ gem install validation_profiler

Usage

First you need to create a validation profile to hold the validation logic you want to apply, validation profiles must inherit from the ValidationProfile base class or another validation profile.

class SignUpValidationProfile
  extend ValidationProfile
  .....
end

Then you specify validation rules that should be checked when this profile is validated against an object.

class SignUpValidationProfile
    extend ValidationProfiler

  validates :age, :min, { value: 18 }
  validates :email, :email
  .....
end

When specifying a validation rule you need to specify the following arguments:

  • Field name
  • Rule key
  • Hash containing any options required for the validation rule

So if we take another look at the first validation rule we specified in the SignUpValidationProfile above:

Field name = :age
Rule key = :min
Attributes Hash = { value: 18 }

This validation statement will be interpreted as: "The field :age must have a minimum value of 18"

To use a validation profile you need to make a call to the ValidationManager class, and pass the object you want to validate along with the profile you want to use for the validation:

# create the validation manager
manager = ValidationProfiler::Manager.new

# call the validate method and pass the object and profile
result = manager.validate(user, profile)

Calls to the validate method will return a ValidationProfiler::ManagerResult that will detail the results of the validation.

A ValidationProfiler::ManagerResult has the following attributes:

  • #outcome = [Boolean] overall outcome of the validation (passed or failed)
  • #errors = [Array] containing details of each field error that occurred during validation.

Each item in the errors array has the following attributes:

  • #field = The name of the field that this error occurred for.
  • #message = A message that describes the validation error

Validation Rules

RequiredValidationRule

This rule is used to specify a field must contain a value:

validates :name, :required

Attributes:

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

LengthValidationRule

This rule is used to specify a [String] or [Array] must be of a certain length:

validates :name, :length, { min: 5, max: 10 }

Attributes:

  • :min [Numeric] This is used to specify the minimum length of the field value.

  • :max [Numeric] This is used to specify the maximum length of the field value.

:min & :max can be included together or independently providing at least 1 is specified.

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


MinValidationRule

This rule is used to specify a minimum value a [DateTime] or [Numeric] field must have.

validates :age, :min, { value: 18 }

Attributes:

  • :value [Numeric/DateTime] This is used to specify the minimum value of the field.

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)*


MaxValidationRule

This rule is used to specify a maximum value a [DateTime] or [Numeric] field must have.

validates :age, :max, { value: 25 }

Attributes:

  • :value [Numeric/DateTime] This is used to specify the maximum value of the field.

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed the field contains a value.

True always executes, False only executes when the field contains a value)


EmailValidationRule

This rule is used to specify a field value must contain a valid email address.

validates :email_address, :email, { multiple: true }

Attributes:

  • :multiple [Boolean] [Default=False] [Optional] This is used to allow multiple email addresses to be entered. Addresses should be separated by a comma(,) or semicolon(;)

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


RegexValidationRule

This rule is used to specify a regex pattern that a field value must validate against.

validates :email, :regex, { regex: /^[^@]+@[^@]+\.[^@]+$/ }

Attributes:

  • :regex [Regex] This is used to specify the regex pattern.

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


MatchValidationRule

This rule is used to specify a field value must match the value of another field.

validates :confirm_password, :match, { field: :password }

Attributes:

  • :field [Symbol] This is used to specify the name of the other field this field's value must match.

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


ConditionValidationRule

This rule is used to specify a condition statement.

e.g.

format:

When [:condition_field] [:condition_expression] [:condition_value] then [:field] [:field_expression] [:field_value]

could be read as:

When :age >= 18 then :accept == true

validates :accept, :condition, { condition_field: :age, condition_expression: '>=', condition_value: 18, field_expression: '==', field_value: true }

Attributes:

  • :condition_field [Symbol] This is used to specify the name of the condition field.

  • :condition_expression [String] This is used to specify the expression to use between the condition_field and the condition_value.

Supported expression types: '==' '>' '>=' '<' '<=' '!='

  • :condition_value [String/Numeric/DateTime/nil] This is used to specify the value to use for the condition statement.

  • :field_expression [String] This is used to specify the expression to use between the field's value and the field_value attribute.

  • :field_value [String/Numeric/DateTime/nil] This is used to specify the value to use for the field statement.

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


NotAllowedValidationRule

This rule is used to specify a field must not contain a value:

validates :hidden, :not_allowed

Attributes:

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

ListValidationRule

This rule is used to specify a field value must be within a specified list of accepted values:

validates :name, :list, { list: ['dog','cat','rabbit'] }

Attributes:

  • :list [Array] This is used to specify the list of values that are acceptable for this field.

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


ChildValidationRule

This rule is used to specify a field with a child object should validate against another validation profile:

validates :address, :child, { profile: AddressValidationProfile }

Attributes:

  • :profile [Class] This is used to specify the validation profile to use for the nested child object

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


IntegerValidationRule

This rule is used to specify a field must be a valid Integer

validates :age, :int, { required: false }

Attributes:

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


DecimalValidationRule

This rule is used to specify a field must be a valid Decimal

validates :amount, :decimal, { required: false }

Attributes:

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


DateValidationRule

This rule is used to specify a field must be a valid Date

validates :dob, :date, { required: false }

Attributes:

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


TimeValidationRule

This rule is used to specify a field must be a valid Time. Value can be either full datetime '12-Mar-2016 12:30:10' or seconds since epoch 1476344603.

validates :updated, :time, { required: false }

Attributes:

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


GuidValidationRule

This rule is used to specify a field must be a valid Guid.

validates :id, :guid, { hyphens: true, brackets: true, required: true }

Attributes:

  • :hyphens [Boolean] [Default=false] [Optional] This is used to allow a the guid value to contain hyphens.

  • :brackets [Boolean] [Default=false] [Optional] This is used to allow a the guid value to contain brackets. Both ( & { brackets are supported.

  • :message [String] [Optional] This is used to allow a custom error message to be specified.

  • :required [Boolean] [Default=True] [Optional] This is used to specify if this rule should only be executed when the field contains a value.

True always executes, False only executes when the field contains a value)


##Custom Validation Rules

To create a custom validation rule you must create a class that inherits from the ValidationRule base class and implement the #error_message and #validate methods, see the RequiredValidationRule below as an example:

class RequiredValidationRule < ValidationRule
  #implement this method to return the error message when
  #this rule fails validation
  def error_message(field, attributes = {})
    #check if custom message was specified
    if attributes[:message] == nil
      #return default method
      "#{field} is not valid"
    else
      #return custom message
      attributes[:message]
    end
  end

  def validate(obj, field, attributes = {})
    #attempt to get the field value from the object
    field_value = get_field_value(obj, field)

    if field_value == nil
      return false
    end

    return !field_value.empty?
  end
end

The ValidationRule base class provides the #get_field_value(obj, field) method to cater for fetching the field value from the object to perform the validation against.

This rule can be added to the ValidationProfiler::Manager, e.g.:

validation_manager = ValidationProfiler::Manager.new
validation_manager.add_rule(:custom_required, RequiredValidationRule)

Development

After checking out the repo, run bin/setup to install dependencies. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/sage/validation_profiler. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

This gem is available as open source under the terms of the MIT licence.

Copyright (c) 2018 Sage Group Plc. All rights reserved.