5222d528879c2671daa7230f275bed3818a51278)An empty string and nil are not equivalent, however Ecto currently silently transforms empty strings into nil.
defmodule User do
use Ecto.Schema
import Ecto.Changeset
schema "users" do
field :name, :string
end
def update(data, params) do
data
|> cast(params, ~w(name))
end
end
changeset_1 =
%User{name: ""}
|> User.update(%{name: ""})
IO.inspect(changeset.changes) #=> %{name: nil}
changeset_2 =
%User{name: "Sean"}
|> User.update(%{name: ""})
IO.inspect(changeset.changes) #=> %{name: nil}
There should be no changes in changeset_1, and the result should be an empty string and not a nil value in changeset_2 above.
@stavro Ecto 2.0 introduced something called :empty_values where some values are automatically cast to their default value. For example, if you set field :name, :string, default: "", the value should then always be cast to an empty string when an empty value is found.
@josevalim this is biting us too. It's not clear what you can do with :empty_values. I don't want to set the default to "" because I want to be able to differentiate between "" and nil after the cast. Is there any way to do that?
On Ecto master you can pass the :empty_values option on cast. On 2.1, you can change it manually. Instead of:
struct
|> cast(...)
do:
struct
|> Ecto.Change.change({})
|> Map.put(:empty_values, [])
>| cast(...)
You can always hide it a function to remove the duplication.
If anyone ends up on this page after a frustrating search, one solution to the empty-strings/null problem is to make sure your schema defines a relevant default value for each field, e.g.
field :street2, :string, size: 64, null: false, default: ""
Without the default: "" bit, you may run into trouble when casting data. HTH.
Most helpful comment
If anyone ends up on this page after a frustrating search, one solution to the empty-strings/null problem is to make sure your schema defines a relevant default value for each field, e.g.
Without the
default: ""bit, you may run into trouble when casting data. HTH.