I’ve seen a few examples on using Ecto.Schema
for validations but I can’t seem to find a way to make defaults play nicely. For some background, I’m building a API that aggregate and cleans data before POSTing it to an external HTTP service. Since the external service has tons of optional params and others that I can provide defaults to I wanted to use a_emphasized text_ schema.
defmodule Lead do
use Ecto.Schema
import Ecto.Changeset
@required_fields ~w(device type_id website)a
@primary_key false
embedded_schema do
field :device, :string
field :type_id, :integer, default: 0
field :session_id, :string
field :website, :string, default: "facebook"
field :message, :string
end
def changeset(%__MODULE__{} = lead, params \\ %{}) do
lead
|> cast(params, __schema__(:fields))
|> cast_session_id
|> validate_required(@required_fields)
|> validate_inclusion(:device, ["web", "mobile"])
|> validate_inclusion(:type_id, 0..6)
end
defp cast_session_id(changeset) do
case get_field(changeset, :session_id) do
nil ->
unix_time =
DateTime.utc_now
|> DateTime.to_unix(:milliseconds)
put_change(changeset, :session_id, "no_session_id_#{unix_time}")
_ -> changeset
end
end
end
This works fine for the most part but when trying to get the final map I run into some weirdness.
iex(1)> cs = %Lead{} |> Lead.changeset(%{device: "web"})
#Ecto.Changeset<action: nil,
changes: %{device: "web", session_id: "no_session_id_1503097557106"},
errors: [], data: #Lead<>, valid?: true>
iex(2)> cs.changes
%{device: "web", session_id: "no_session_id_1503097557106"}
iex(3)> Ecto.Changeset.apply_changes(cs)
%Lead{device: "web", message: nil, session_id: "no_session_id_1503097557106",
type_id: 0, website: "facebook"}
If I try and use the changes
, then field defaults don’t work.
If I try to apply_changes
I get fields with nil
.
I see two options, I could either move the default
into a cast like cast_session_id
or I could just filter out keys with nil
values. The real schema has 15 optional fields with 5 or so fields that I could provide defaults.
Thoughs / Suggestions?