houdini/gems/ruby-param-validation
2019-08-02 19:07:29 +02:00
..
lib style(format): run rubocop format autocorrect 2019-08-02 19:07:29 +02:00
test style(format): run rubocop format autocorrect 2019-08-02 19:07:29 +02:00
LICENSE Add ruby-param-validation to repo 2019-01-09 18:22:42 -06:00
param_validation.gemspec style(format): run rubocop format autocorrect 2019-08-02 19:07:29 +02:00
Rakefile style(format): run rubocop format autocorrect 2019-08-02 19:07:29 +02:00
README.md Add ruby-param-validation to repo 2019-01-09 18:22:42 -06:00

ParamValidation

A standalone and simple ruby hash validation lib, useful for validating the data passed to your functions.

new_charge_validation = {
  amount: {
    required: true
  },
  stripe_card_token: {
    required: true,
    format: /^tok_.*$/
  }
}

def update_database(data)
  ParamValidation.new(data, new_charge_validation)
  # do stuff
  return result
end

The above checks the :amount and :stripe_card_token keys inside the data hash and runs validations on them. If a value is invalid, an exception is thrown. The exception can be handled outside your function call, typically in a controller/router or in a test suite.

An exception is thrown for each failure.

ParamValidation::Error

The ParamValidation::Error object has the following information on it:

begin 
  update_database(data)
rescue ParamValidation::Error => e
  e.message # string validation failure message
  e.val     # value that failed validation
  e.key     # key name of the above value inside the data hash
  e.name    # name of the validator that failed
rescue Exception => e
  # a non-validation exception
end

Using in Rails

To handle validation exceptions from the controller, you can add a custom helper function in your ApplicationController like this:

def render_json(&block)
  begin
    result = yield block
  rescue ParamValidation::Error => e
    return {status: 422, json: {error: e.message, key: e.key}}
  rescue Error => e # a non-validation related exception
    return {status: 500, json: e}
  end
  return {status: 200, json: result}
end

With the above, you can simply call render_json on your validated function call:

UsersController < ApplicationController
  def update
    render_json{ update_user(params[:user]) }
  end
end
update_validation = {
  email: {
    presence: :optional,
    format: email_regex
  }
}

def update_user(params)
  ParamValidation.new(params, update_validation)
end

built-in validators

  • required: value must be non-nil
  • absent: value must be nil
  • not_included_in: value must not be in array
  • included_in: value must be in array
  • format: value must match regex
  • is_integer: value must look like an integer (can be a string)
  • is_float: value must look like a float (can be a string)
  • min_length: array value must have length >= min
  • max_length: array value must have length <= max
  • length_range: array value must have length within given range
  • length_equals: array value length must equal given arg
  • equals: value must equal given arg
  • min: value must be >= arg
  • max: value must be <= arg
  • in_range: value must be within the given range

custom validators

ParamValidation.add_validator takes a name and a block. That block performs the validations and simply returns true/false. The block takes three params: the actual value to validate, and the argument provided in the validation hash, and the entire data hash being validated.

# You can use other validators inside a new validator
ParamValidation.add_validator(:dollars) do |val, arg, data|
  ParamValidation.validators[:format](val, /^\$\d+\.(\d\d)$?, data)
end

# # Validators that don't need an argument typically just get 'true' passed in
# ParamValidation.new(params, { 
#   amount: { dollars: true }
# })

# Other examples

# Uniqueness validation (of course it may be better to use the UNIQUE constraint in sql)
ParamValidation.add_validator(:unique) do |val, arg, data|
  Qx.select("COUNT(*)").from(:table).where(name: val).first['count'] == 0
end

custom validation messages

Within a validation instance, you can set a custom message with the :message key.

ParamValidation.new(params, {
  amount: {
    dollars: true,
    message: 'Please enter a dollar amount'
  }
})

To change the global default message, simply use ParamValidation.set_message(:validation_name, &block).

ParamValidation.set_message(:dollars) do |h|
  "#{h[:key]} must be in dollars"
end

The set_message block receives a hash with some data:

  • :key - name of the key in the hash that failed this validation
  • :arg - argument to validator (eg format regex)
  • :val - actual value that failed validation
  • :data - entire data hash that is being validated

internationalization -- TODO!

Internationalization support is not yet in place; please make a PR for it!