Repository navigation
Validating data with ecto changesets and no database
I would like to validate some user input that doesn't directly map to a database column and would like to be able to use the validation's output as if it were a normal database-backed model. How do I do that?
Ecto.Changesets require just three things to validate data:
- a cast to specified type
- validation(s) of data
- apply_action(:validate)
If you wanted to verify a number input by a user was say a number and above 5, you might write something like the following to check that value:
# some controller
def verify(conn, params) do
case SomeContext.verify_enough(params) do
{:ok, value} ->
conn
|> put_status(200)
|> assign(:value, value)
|> render("show.json")
{:error, changeset} ->
conn
|> put_status(422)
|> assign(:changeset, changeset)
|> put_view(Web.ErrorView)
|> render("changeset.json")
end
end
# some context
def verify_enough(params) do
case SomeEctoModel.validate_high_enough_value(params) do
{:ok, data} ->
data.value
{:error, changeset} ->
{:error, changeset}
end
end
# some ecto model
def validate_high_enough_value(params) do
types = %{value: :integer}
{%{}, types}
|> cast(params, Map.keys(types))
|> validate_required([:value])
|> validate_number(:value, greater_than: 5)
|> apply_action(:validate)
end
This is as simple as you can get, but you can imagine integrating this changeset into a larger one that may save something to the database if that's necessary. The important thing is you are validating type and value of user input without having to write one-off methods to do so, but instead of using familiar machinery from Ecto.
🏳️🌈🦄 Sharing is caring. 🦄🏳️🌈
TODO: can we recreate the tag system here roughly with sections about certain subjects?