Is there a way of putting postgres errors into the changeset?

I’ve created a new phoenix project with the --binary-id and --live options. I used a liveview generator to create a Restaurant schema and a MenuItem schema where MenuItem references the restaurant_id. I’m getting this error when doing a test insert of a menu_item that references a restaurant_id and getting this error:

value "5" for (restaurant_id) in insert does not match type :binary_id

This error is displayed in iex when manually doing an insert, and this is expected since 5 is not a UUID, not is it correctly referencing any id in restaurants. But in the UI since the process crashed I don’t see an error in the form. In practice this particular error should never happen since I don’t plan on allowing my users to directly type in the restaurant UUID, but I’m just thinking in general shouldn’t there be a way to surface the error into the changeset?

Is the only way to do a rescue around the Repo.insert and manually put the error into the changeset?

This kind of errors can be caught before touching Postgres using Ecto.UUID type.
Here is example:

> types = %{id: Ecto.UUID}
%{id: Ecto.UUID}

> {%{}, types} |> Ecto.Changeset.cast(%{id: "5"}, [:id])
#Ecto.Changeset<
  action: nil,
  changes: %{},
  errors: [id: {"is invalid", [type: Ecto.UUID, validation: :cast]}],
  data: %{},
  valid?: false
>

> {%{}, types} |> Ecto.Changeset.cast(%{id: UUID.uuid4}, [:id])
#Ecto.Changeset<
  action: nil,
  changes: %{id: "71973364-3444-4b35-9594-b668a331397e"},
  errors: [],
  data: %{},
  valid?: true
>
1 Like

That was helpful thanks. I guess I didn’t know what the difference between binary_id and Ecto.UUID was. I thought the generators would already setup everything for me geared toward UUID since I initialized the app with the --binary-id flag. But I suppose binary_id is just a string and it doesn’t know how to validate itself as a proper UUID which is a particular kind of binary_id, of which binary_id is agnostic about since there could be many other kinds of binary_id.

So all I had to do was replace binary_id in my schemas with Ecto.UUID. Afterwards I still got a raised error when the foreign key constraint was violated, but the error was very clear on how to bring the error into the changeset. I just needed to add foreign_key_constraint/3 and now it works as expected.