backpex icon indicating copy to clipboard operation
backpex copied to clipboard

add chance to send base errors from after save actions

Open tommasop opened this issue 10 months ago • 2 comments

@Flo0807 this small change makes it possible to pop up errors from the on_item_updated action.

I'm using an Ash flow that needs to sync data across different legacy services if any of the steps fail I rollback everything and I need to show a syncing error flash.

I'm pattern matching on a :base changeset error so that the actual behavior can remain untouched.

This is the implementation on my service:

  def on_item_updated(socket, item) do
    case reactor_module().run(
           IdentityUpdater,
           %{
             identity: item,
             identity_params:
               Map.from_struct(socket.assigns.item) |> Map.reject(fn {k, _v} -> is_binary(k) end)
           }
         ) do
      {:ok, _result} ->
        {:ok, item}

      {:error, reason} ->
        Logger.error(reason)

        backpex_error =
          "An error occurred while syncing the #{socket.assigns.singular_name}!"

        changeset =
          socket.assigns.changeset
          |> Ecto.Changeset.add_error(:base, backpex_error)

        socket
        |> assign(:changeset, changeset)

        {:error, changeset}
    end
  end

tommasop avatar Apr 02 '25 16:04 tommasop

Hey @tommasop!

I guess, using a changeset error as a workaround to display an error flash message is not the right way.

Still, the code would persist the item to the database because on_item_updated is called after the database call.

From my understanding, changeset errors should be a result of failed validations that prevent the item from being saved and to display validation errors / constraints to users. We should continue to use changesets in that way, not to put text into flash messages.

Therefore, we should find a more generic way of supporting your use case.

A few ideas:

  • We can make it possible to put a flash into the socket from on_item_updated.
  • We can add a on_item_updating callback that is called before database calls to perform such tasks like you do with syncing. Such a callback might also be allowed to put changeset errors.

Flo0807 avatar Apr 03 '25 06:04 Flo0807

@Flo0807 yeah you are right, I just whipped up something with what was already available.

Your solutions are both working for me but what I would like is to completely override the Resource.update action.

tommasop avatar Apr 03 '25 09:04 tommasop

Hey, I close this MR.

You are welcome to submit another one with a more generic solution mentioned above!

Flo0807 avatar Jul 25 '25 10:07 Flo0807