4
votes

I am relying on Ecto to return an error when an insert fails a database level constraint.

Is it possible to run different code depending on the error type returned by Ecto?

case Repo.insert(changeset) do
        {:ok, _} ->
            IO.puts("inserted")
        {:error, message} when is_certain_ecto_error ->
            IO.puts("database constraint error")
        {:error, message}  ->
            IO.puts("everything else error")
end
2
Ecto will return a {:error, changeset} tuple when an insert fails. You will need to look at the errors and decide what to do. - Justin Wood
So a full blown string check? Is there a nice way to type check against a Ecto.ConstraintError - henry.oswald

2 Answers

4
votes

Like Justin said, you will get {:error, changeset}, the changeset would have the errors keyword list, where you can pattern match on.

case Repo.insert(changeset) do
    {:ok, _} -> 
        IO.puts("inserted")
    {:error, %{ errors: errors }} ->                  
        Enum.map(errors, &handle_error(&1))
end

defp handle_error({:user_name, {message, _}}) do
   "User name error:" <> message
end
defp handle_error({_some_key, _error_tuple}), do: "some error"
0
votes

You can always rewrite your code to use try / rescue block or simple pattern match against Ecto.ConstraintError, since it's nothing more than a struct.

You can use simple pattern matching against that struct or even against map.

case error do
   %Ecto.ConstraintError{} -> do_something()
   _ -> do_something_else()
end

The best solution in my opinion is to create a function that handles all of the errors you can get and use pattern matching in function signature eg.

def handle_error_from_ecto(%Ecto.ConstraintError{} = error) do
  # do something here
end