Writing Custom Validations for Ecto Changesets Part 1

Duplicated from Medium

We often need to validate fields that are passed through a struct in Ecto Changesets. Custom validations are very straightforward to write and can be composed with one another easily. By using validate_change/3 which invokes a validator function, the function returns either a) the changeset or b) the changeset with errors if the validation fails.

Let’s take a look at a changeset with a custom validation validate_from_s3_bucket:

@our_url "https://our-bucket.s3.amazon.com"
def changeset(struct, params \\ %{}) do
  struct
  |> cast(params, @required_fields)
  |> validate_required(@required_fields)
  |> validate_from_s3_bucket(:url)
end
def validate_from_s3_bucket(changeset, field, options \\ []) do
  validate_change(changeset, field, fn _, url ->
    case String.starts_with?(url, @our_url) do
      true -> []
      false -> [{field, options[:message] || "Unexpected URL"}]
    end
  end)
end
validate_change/3: https://hexdocs.pm/ecto/Ecto.Changeset.html#validate_change/3

Here, we simply pass a new function validate_from_s3_bucket/2 to our changeset, which returns the changeset with no changes or with errors added. We can just as easily compose validations on top of one another in the form of validation functions that get piped to each other, which gives us our code a great deal of readability and flexibility.

Sign up for our newsletter

Get notified of any new episodes as we release them.

© 2020 QuantLayer, LLC. All rights reserved.