2

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()??

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

Don't use this:

    Changeset.change(data_from_db, new_data)

Just run the same function you were already using:

    Data.changeset(data_from_db, new_data)

By the way, you can actually simplify this function a lot:

  def add_or_change(user_id, new_data) do
    (data_by_user_id(user_id) || %Data{})
    |> Data.changeset(new_data)
    |> Repo.insert_or_update()
  end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.