Writing Custom Validations for Ecto Changesets Part 2

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 "https://s3.amazonaws.com/our-bucket"
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")
      end
    _ ->
      changeset
  end
end

We then pass this function to our changeset:

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

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

test "changeset with valid url format" do
  good_url = "https://s3.amazonaws.com/our-bucket/happy-cow.jpg"
  changeset = Photo.changeset(%Photo{url: good_url})
  
  assert changeset.valid?
end
test "changeset with invalid url format" do
  bad_url = "https://s3.amazonaws.com/other-bucket/happy-lamb.jpg"
  changeset = Photo.changeset(%Photo{url: bad_url})
  
  refute changeset.valid?
end

That’s it!

Sign up for our newsletter

Get notified of any new episodes as we release them.

© 2020 QuantLayer, LLC. All rights reserved.