More Custom Validations for Ecto Changesets

By Vikram Ramakrishnan

Validating changesets in Ecto can be really simple. We previously wrote about using validate_change/3 to validate changesets here:

While working through other custom validations, we came across another straightforward method of validating changesets. We can write a function that takes a changeset and returns it if valid and fits our requirements, or returns the changeset with errors added:

In our previous example, we covered validating that the url string field was in a specific AWS bucket. Here is another version of that example here:

@url ""
defp validate_url_format(changeset, field) do
case changeset.valid? do
true ->
url = get_field(changeset, field)
case String.starts_with?(field, @url) do
true -> changeset
_ -> add_error(changeset, :url, "Format invalid")
_ ->

We then pass this function to our changeset:

def changeset(struct, params \\ %{}) do
|> cast(params, [:url])
|> validate_required([:url])
|> unique_constraint(:url)
|> validate_url_format(:url)

We can write a couple quick tests to test that this works as well:

test "changeset with valid url format" do
good_url = ""
  changeset = Photo.changeset(%Photo{url: good_url})

assert changeset.valid?
test "changeset with invalid url format" do
bad_url = ""
  changeset = Photo.changeset(%Photo{url: bad_url})

refute changeset.valid?

That’s it!

Interested in discussing custom software needs more broadly? Drop me a line at — I would love to chat with you. Follow us on Twitter at