View Source Validations
Builtin Validations
Checkout the documentation for Ash.Resource.Validation.Builtins
to see the builtin validations.
Some examples of usage of builtin validations
validate match(:email, ~r/@/)
validate compare(:age, greater_than_or_equal_to: 18) do
message "must be over 18 to sign up"
end
validate present(:last_name) do
where [present(:first_name), present(:middle_name)]
message "must also be supplied if setting first name and middle_name"
end
Custom Validations
defmodule MyApp.Validations.IsPrime do
# transform and validate opts
def init(opts) do
if is_atom(opts[:attribute]) do
{:ok, opts}
else
{:error, "attribute must be an atom!"}
end
end
def validate(changeset, opts) do
value = Ash.Changeset.get_attribute(changeset, opts[:attribute])
# this is a function I made up for example
if is_nil(value) || Math.is_prime?(value) do
:ok
else
# The returned error will be passed into `Ash.Error.to_ash_error/3`
{:error, field: opts[:attribute], message: "must be prime"}
end
end
end
This could then be used in a resource via:
validate {MyApp.Validations.IsPrime, attribute: :foo}
Where
The where
can be used to perform changes/validations conditionally. This functions by running the validation, and if the validation returns an error, we discard the error and skip the operation. This means that even custom validations can be used in conditions.
For example:
validate present(:other_number) do
where [{MyApp.Validations.IsPrime, attribute: :foo}]
end
Action vs Global Validations
You can place a validation in any create, update, or destroy action. For example:
actions do
create :create do
validate compare(:age, greater_than_or_equal_to: 18)
end
end
Or you can use the global validations block to validate on all actions of a given type. Where statements can be used in either. Use on
to determine the types of actions the validation runs on. By default, it only runs on create an update actions
validations do
validate present([:foo, :bar], at_least: 1) do
on [:create, :update]
where present(:baz)
end
end