4.3 KiB
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!