Clean way to get error messages from Ecto.changeset

If I want to get the first error message from Ecto.Changeset, here’s what I have to do:

error_msg = changeset.errors
        |> hd()
        |> Tuple.to_list()
        |> tl()
        |> hd()
        |> Tuple.to_list()
        |> hd()

As you can see, it’s very troublesome. Any idea how to fix it?

How about pattern matching it? That’s how I extract error messages in my tests.

Phoenix provides the following helper when you use AppName.DataCase in your tests

This doesn’t give you the “first” error, but you can use it to check errors in any order you’d like.

  @doc """
  A helper that transforms changeset errors into a map of messages.

      assert {:error, changeset} = Accounts.create_user(%{password: "short"})
      assert "password is too short" in errors_on(changeset).password
      assert %{password: ["password is too short"]} = errors_on(changeset)

  """
  def errors_on(changeset) do
    Ecto.Changeset.traverse_errors(changeset, fn {message, opts} ->
      Regex.replace(~r"%{(\w+)}", message, fn _, key ->
        opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string()
      end)
    end)
  end
1 Like