I have an ecto schema backed by a table that has a non_null column with a default. I want to add a validation that will check that column is in an enum of values:
changeset
|> Validations.validate_field_in_enum(:lead_status, ["active", "inactive"])
def validate_field_in_enum(changeset, field, enum) do
field =
changeset
|> Ecto.Changeset.apply_changes()
|> Map.get(field)
if field in enum do
changeset
else
add_error(changeset, field, "Invalid #{field}", validation: field)
end
end
The problem is when I call Ecto.Changeset.apply_changes(), the struct returned will not include the default value the DB will eventually give the column I am checking. That means, when the record is being created without that specific field in the changes, I can't validate it. As the field comes back as nil.
That the struct returned will contain that value.
So say a default on a field is something like "someDatabaseFunction()", what would you expect the default to be? Defaults are database-side, not Elixir side, as only the database can truly know. If a database can do the validation of something then it probably should do the validation. :-)
Since the only way to access the database is through Repo, when it's not used we don't touch database (this is one of the basic guarantees of Ecto). This means there isn't even a way to make it work even if we wanted to.
Probably the only way to read the database defaults (if you really need to do this) would be to insert the value in a transaction just to immediately rollback.
Sorry to re-open the issue, but it appears that it doesn't seem to work with Repo.insert either.
if I do something like:
%MyStruct{}
|> create_and_validate_changeset(%{foo: "bar"})
|> MyApp.Repo.insert()
The struct I am returned doesn't reflect the DB - the default boolean field gets set to null in the DB, but not in the struct returned from the Repo.insert.
I can fix this by adding a default to the model, is that what I am meant to do? Or should the insert return what the DB has?
Yes, use :default or read_after_write: true for a given field in your schema definition.
Ahh yes read_after_writes that鈥檚 what i was trying to remember!! Thanks
Why is read_after_writes not the default though?
Jos茅 Valim
www.plataformatec.com.br
Skype: jv.ptec
Founder and Director of R&D
Most helpful comment
Since the only way to access the database is through
Repo, when it's not used we don't touch database (this is one of the basic guarantees of Ecto). This means there isn't even a way to make it work even if we wanted to.Probably the only way to read the database defaults (if you really need to do this) would be to insert the value in a transaction just to immediately rollback.