Atoms and Ecto custom types
Published on 2021-01-04
3m read
elixir, functional programming, ecto
Working on siteguardian.dev I ran into an issue trying to save an embedded schema like:
defmodule Result do
embedded_schema do
field :status, CheckStatusEnum
field :code, :string
field :message, :string
field :payload, :map
end
end
Which was failing with the following error:
{:error,
#Ecto.Changeset<
action: :insert,
changes: %{
...
errors: [code: {"is invalid", [type: :string, validation: :cast]}],
data: #Result<>,
valid?: false
>
],
},
...
}
So Ecto
will by default not handle the atom
passed as the attributes for the result. The solution happened to be pretty straightforward, define a custom Ecto type to handle atoms:
defmodule Siteguardian.Util.AtomType do
@moduledoc false
use Ecto.Type
def type, do: :string
def cast(value), do: {:ok, value}
def load(value), do: {:ok, String.to_atom(value)}
def dump(value) when is_atom(value), do: {:ok, Atom.to_string(value)}
def dump(_), do: :error
end
The magic here happens on the dump/1
and load/1
functions; convert atom to string on the way in and convert string to atom on the way out.