Search code examples
validationelixirectochangeset

Why Changeset.change is skipping validation in Elixir?


This is a simple function used to insert or update some data. If user data is already in db i simply update it, otherwise i insert a new row with data. Everything works fine but i have a problem with validation. Changeset definition:

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:name, :surname, :user_id])
    |> validate_required([:name, :surname, :user_id])
    |> unique_constraint(:user_id)
  end

validate_required is currently working only during insert and not during update.

  def add_or_change(user_id, new_data) do
    data_from_db = data_by_user_id (user_id)
    case data_from_db do
      nil ->
        Data.changeset(%Data{}, new_data)
        |> Repo.insert()

      _ ->
        Changeset.change(data_from_db, new_data)
        |> Repo.update()
    end
  end

If i try to insert "" as :name value, i get an error (can't be blank) as expected. However if i'm updating an existing row with "" as :name value, changeset does not pass through validation and my db is updated improperly. How to force validation also on change, before Repo.update()??


Solution

  • According to the doc: Ecto.Changeset/2 is meant for internal data changes, so it bypasses validations:

    The function is meant for working with data internal to the application. Because of that neither validation nor casting is performed. This means change/2 expects the keys in the changes map or keyword to be atoms.

    You should use Ecto.Changeset.cast/4 to apply the validations, and then update if it is valid.