The issue with @Alekseis answer is the syntax:
%{changeset | uuid: String.pad_leading(uuid, 8, "0")}
First of all the changes would live in changeset.changes, so for example changeset.changes.uuid. But they are only there when there are actually changes for this attribute. So writing
%{changeset.changes | uuid: String.pad_leading(uuid, 8, "0")}
will not help us, since this syntax only works if the key already exists in the map. We could do something like this:
Map.put(changeset, :uuid, String.pad_leading(uuid, 8, "0")
but I recommend to use the appropriate functions from Ecto.Changeset, since a changeset might only be a struct, but there is quite some logic around it. Our friend is: https://hexdocs.pm/ecto/Ecto.Changeset.html#put_change/3
So let's rewrite the solution:
@spec prepend_zeroes_to_uuid(Ecto.Changeset.t()) :: Ecto.Changeset.t()
# There are changes on uuid but it already is 8 characters long
def prepend_zeroes_to_uuid(%{changes: %{uuid: uuid}} = changeset)
when is_binary(uuid) and byte_size(uuid) >= 8, do: changeset
# There are changes on uuid and it needs padding
def prepend_zeroes_to_uuid(%{changes: %{uuid: uuid}} = changeset) when is_binary(uuid) do
put_change(changeset, :uuid, String.pad_leading(uuid, 8, "0"))
end
# There are no changes on uuid
def prepend_zeroes_to_uuid(changeset), do: changeset
# Now in your pipeline:
user
|> User.changeset(%{uuid: new_uuid})
|> prepend_zeroes_to_uuid()
|> Repo.update()