Ignoring validation errors when deleting a model

Hi. I’m using the maybe_mark_for_deletion technique as described here:
https://hexdocs.pm/ecto/Ecto.Changeset.html

The problem is if the user enters invalid data before they delete the item, then the validation errors show up instead of just deleting the item.

  def changeset(model, params \\ %{}) do
    model
    |> cast(params, ~w(blah foo age))
    |> validate_required([:age])
    |> validate_number(:age, greater_than: 0)
    |> mark_for_deletion
  end

  defp mark_for_deletion(changeset) do
    if get_change(changeset, :delete) do
      %{ changeset | action: :delete }
    else
      changeset
    end
  end

So if someone changes their age to 0 before deleting the item, it shows validation errors instead of just deleting it.

In my mark_for_deletion function, I suppose since it’s the last function in the pipe, it can simply force :valid? to true and errors to []… but that feels like I’m messing with internal APIs.

Any ideas? Thanks for the help.

P.S. Using ecto-2.0-rc

1 Like

It seems to me like the whole validation pipeline does not make sense whenever it is marked for deletion.

So you might want to do something like:

  def changeset(model, params \\ %{}) do
    model
    |> cast(params, ~w(blah foo age))
    |> maybe_mark_for_deletion
    |> run_validations
  end

  defp maybe_mark_for_deletion(changeset) do
    if get_change(changeset, :delete) do
      %{ changeset | action: :delete }
    else
      changeset
    end
  end
  
  # Skip validations when the element will be deleted.
  defp run_validations(changeset = %{action: :delete}), do: changeset

  defp run_validations(changeset) do
    changeset
    |> validate_age(changeset)
  end

  defp validate_age(changeset) do
    changeset
    |> validate_required([:age])
    |> validate_number(:age, greater_than: 0)
  end
2 Likes

Cool. This also works:

  defp maybe_mark_for_deletion(changeset) do
    if get_change(changeset, :delete) do
      %{ changeset | action: :delete, , valid?: true, errors: [] }
    else
      changeset
    end
  end

And just make sure that runs last in the changeset pipe.

2 Likes