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: https://medium.com/@QuantLayer/writing-custom-validations-for-ecto-changesets-4971881c7684

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!

Interested in discussing custom software needs more broadly? Drop me a line at vikram@quantlayer.com — I would love to chat with you. Follow us on Twitter at https://twitter.com/@QuantLayer