class Athena::Validator::Constraints::Callback
inherits Athena::Validator::Constraint
#
Allows creating totally custom validation rules, assigning any violations to specific fields on your object. This process is achieved via using one or more callback methods which will be invoked during the validation process.
Note
The callback method itself does fail or return any value.
Instead it should directly add violations to the AVD::ExecutionContextInterface
argument.
Configuration#
Required Arguments#
callback#
Type: AVD::Constraints::Callback::CallbackProc?
Default: nil
The proc that should be invoked as the callback for this constraint.
Note
If this argument is not supplied, the callback_name argument must be.
callback_name#
Type: String?
Default: nil
The name of the method that should be invoked as the callback for this constraint.
Note
If this argument is not supplied, the callback argument must be.
Optional Arguments#
Note
This constraint does not support a message
argument.
groups#
Type: Array(String) | String | Nil
Default: nil
The validation groups this constraint belongs to.
AVD::Constraint::DEFAULT_GROUP
is assumed if nil
.
payload#
Type: Hash(String, String)?
Default: nil
Any arbitrary domain-specific data that should be stored with this constraint.
The payload is not used by Athena::Validator
, but its processing is completely up to you.
Usage#
The callback constraint supports two callback methods when validating objects, and one callback method when using the constraint directly.
Instance Methods#
To define an instance callback method, apply the @[Assert::Callback]
method to a public instance method defined within an object.
This method should accept two arguments: the AVD::ExecutionContextInterface
to which violations should be added,
and the AVD::Constraint@payload
from the related constraint.
More than one callback method can exist on a type, and the method name does not have to be validate
.
class Example
include AVD::Validatable
SPAM_DOMAINS = ["fake.com", "spam.net"]
def initialize(@domain_name : String); end
@[Assert::Callback]
def validate(context : AVD::ExecutionContextInterface, payload : Hash(String, String)?) : Nil
# Validate that the `domain_name` is not spammy.
return unless SPAM_DOMAINS.includes? @domain_name
context
.build_violation("This domain name is not legit!")
.at_path("domain_name")
.add
end
end
Class Methods#
The callback method can also be defined as a class method. Since class methods do not have access to the related object instance, it is passed in as an argument.
That argument is typed as AVD::Constraints::Callback::Value
instance which exposes a AVD::Constraints::Callback::Value#get
method that can be used as an easier syntax than .as
.
class Example
include AVD::Validatable
SPAM_DOMAINS = ["fake.com", "spam.net"]
@[Assert::Callback]
def self.validate(value : AVD::Constraints::Callback::ValueContainer, context : AVD::ExecutionContextInterface, payload : Hash(String, String)?) : Nil
# Get the object from the value, typed as our `Example` class.
object = value.get self
# Validate that the `domain_name` is not spammy.
return unless SPAM_DOMAINS.includes? object.domain_name
context
.build_violation("This domain name is not legit!")
.at_path("domain_name")
.add
end
def initialize(@domain_name : String); end
getter domain_name : String
end
Procs/Blocks#
When working with constraints in a non object context, a callback passed in as a proc/block.
AVD::Constraints::Callback::CallbackProc
alias can be used to more easily create a callback proc.
AVD::Constraints::Callback.with_callback
can be used to create a callback constraint, using the block as the callback proc.
See the related types for more information.
Proc/block based callbacks operate similarly to Class Methods in that they receive the value as an argument.
Constructors#
.new(callback : AVD::Constraints::Callback::CallbackProc | Nil = nil, callback_name : String | Nil = nil, groups : Array(String) | String | Nil = nil, payload : Hash(String, String) | Nil = nil)
#
Class methods#
.with_callback : AVD::Constraints::Callback
#
Convenience method for creating a AVD::Constraints::Callback
with
the given &block as the callback.
# Instantiate a callback constraint, using the block as the callback
constraint = AVD::Constraints::Callback.with_callback do |value, context, payload|
next if (value = value.get(Int32)).even?
context.add_violation "This value should be even."
end
Methods#
#callback : AVD::Constraints::Callback::CallbackProc | ::Nil
#
Returns the proc that this constraint should invoke.
#callback_name : String | ::Nil
#
Returns the name of the callback method this constraint should invoke.
#validated_by : AVD::ConstraintValidator.class
#
Returns the AVD::ConstraintValidator.class
that should handle validating self
.