Validate Ecto belongs_to field format

Is there any built in solution to validate the “format” of a belongs_to field ?

I have a schema with a belongs_to field (type :binary_id)

   # item.ex
  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id

  schema "items" do
    field(:name, :string)
    belongs_to(:category, Category, foreign_key: :category_id)
  end

And when I try to validate a payload containing an invalid UUID format, no error are triggered:

iex(1)> item = %{"name": "my_item", "category_id": "63882a9a-ce71-4419-95c8-ce863a3de1d8_not_valid"}
%{category_id: "63882a9a-ce71-4419-95c8-ce863a3de1d8_not_valid", name: "my_item"}
iex(2)> Item.changeset(%Item{}, item)
#Ecto.Changeset<
  action: nil,
  changes: %{category_id: "63882a9a-ce71-4419-95c8-ce863a3de1d8_not_valid", name: "my_item"},
  errors: [],
  data: #Item<>,
  valid?: true
>

Why this does not trigger an error ? Like it does when name field is not valid:

iex(3)> item = %{"name": 0, "category_id": "63882a9a-ce71-4419-95c8-ce863a3de1d8_not_valid"}
%{category_id: "63882a9a-ce71-4419-95c8-ce863a3de1d8_not_valid", name: 0}
iex(4)> Item.changeset(%Item{}, item)
#Ecto.Changeset<
  action: nil,
  changes: %{fleet_id: "63882a9a-ce71-4419-95c8-ce863a3de1d8_not_valid"},
  errors: [name: {"is invalid", [type: :string, validation: :cast]}],
  data: #Item<>,
  valid?: false
>

Try to change type from :binary_id to Ecto.UUID.

1 Like

Actually, that’s my bad and I didn’t needed to change anything. Validation is working fine, error was on another spot.

But I am curious now, what does this change to use Ecto.UUID instead of :binary_id ?

They have different casting rules.

iex> Ecto.Type.cast(:binary_id, "test")
{:ok, "test"}
iex> Ecto.Type.cast(Ecto.UUID, "test") 
:error
iex> Ecto.Type.cast(:binary_id, "049bd93d-b9e6-4824-b314-4e6c57a1cd25")
{:ok, "049bd93d-b9e6-4824-b314-4e6c57a1cd25"}
iex> Ecto.Type.cast(Ecto.UUID, "049bd93d-b9e6-4824-b314-4e6c57a1cd25") 
{:ok, "049bd93d-b9e6-4824-b314-4e6c57a1cd25"}
1 Like