May 20, 2015

Useful Ecto Validators

Over the past week, I’ve created a couple custom validators for my Elixir projects which use Ecto. Since validators are just functions that take a changeset and return a changeset, they’re very easy to write.

I’ll update this post in the future if I find or write any more useful validators, or refactor ones I’ve already written.

validate_url

This validator will ensure that a URL is parseable by the Erlang http_uri module. I obviously could have gone for a huge regular expression here, but this seemed a little more trustworthy.

def validate_url(changeset, field, options \\ []) do
  validate_change changeset, field, fn _, url ->
    case url |> String.to_char_list |> :http_uri.parse do
      {:ok, _} -> []
      {:error, msg} -> [{field, options[:message] || "invalid url: #{inspect msg}"}]
    end
  end
end

Usage

validate_url(changeset, :url, message: "URL is not a valid URL!")

validate_array_inclusion

I wrote this validator because of PostgreSQL’s Array field type. Ecto already has a validate_inclusion validator which will ensure that a given value is a member of a given array. However, in order to validate a Postgres array field, I needed to validate that all members of array A are also members of array B.

This function does the trick:

def validate_array_inclusion(changeset, field, allowed, options \\ []) do
  validate_change changeset, field, fn _field, values ->
    valid? = Enum.all? for value <- values, do: value in allowed
    if valid?, do: [], else: [{field, options[:message] || "is invalid"}]
  end
end

Usage

validate_array_inclusion(changeset, :notify, ~w(email sms phone), message: "custom message here")

This will ensure that the “notify” array only contains some subset of the values ["email", "sms", "phone"].

Did You Enjoy This Post?