Ecto apply action and defaullt values in the DB

I have a table with a non_null column that has a default.

I want to do some validations on the changeset. To be able to do these validations, I need to call

Ecto.Changeset.apply_changes(changeset)

The problem is the returned struct will not contain the default value that the db column will eventually enforce on it. Is this a bug, or intended behaviour?

It’s making it impossible to get the validations I want.

Intended behaviour depending on the type as the database itself should fill those in itself (thus potentially saving a lot of bandwidth in certain cases, plus many defaults just cannot be calculated by elixir and have to be done by the database).

What validations are you wanting that are difficult?

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.

Hmm, better question I think, why are you applying changes when you are going to give it to the database?

EDIT: Also if using Postgrex you should use that EctoEnum library or whatever it was called, that will let the database itself not only confirm but also enforce the enumerated values (which you can do manually via a custom type or a foreign table depending on whether it should be dynamic or not). :slight_smile:

1 Like

That’s true I could make it a proper enum, havent looked into that. I think maybe I’ve confused myself

1 Like

It’s just easy to fall in to thinking that the server should do data validation which is what the data store itself should do that, I fall in to that sometime, but a database is fantastic at all this work. :slight_smile:

I fixed it, I just added a default to the schema! Didn’t know you could do that in Ecto