TZWZ's personal page
Showing error flash or ignore result waiting for PubSub message on DB action
13.08.2025
Elixir
Phoenix
Phoenix LiveView

When writting LiveView applications most of my DB actions/calls that changed rows were doing INSERT/UPDATE/DELETE operation then broadcast call on PubSub so everyone connected to given view, interested in changes to given thing can get updated version, so everyone can see most recent version of the thing. This means that whichever piece of code does change in DB also listens to changes in it. Because of that, we can either deal with the new result after we get it or ignore it and wait for a message from PubSub.

The solution for this problem is pretty simple. Let's start by creating module MyAppWeb.Flash.

defmodule MyAppWeb.Flash do
  alias Phoenix.LiveView

  def result_flash(result, socket) do
    case result do
      :ok -> LiveView.put_flash(socket, :info, "Success!")
      {:ok, _} -> LiveView.put_flash(socket, :info, "Success!")
      {:error, reason} -> LiveView.put_flash(socket, :error, reason)
    end
  end
end

With this, when we have a schema operation returned, we can show a success flash or error flash with just simple pipes and go on with our lives, waiting for PubSub message. For example:

defmodule MyAppWeb.Live.SomeView do
  use MyAppWeb, :live_view

  def mount(_params, _session, socket) do
    if connected?(socket) do
      MyApp.SomeSchema.subscribe()
    end

    {:ok, assign(socket, values: MyApp.SomeSchema.all())}
  end

  def handle_event("new", form, socket) do
    {:noreply, form |> MyApp.SomeSchema.new() |> MyAppWeb.Flash.result_flash(socket)}
  end

  def handle_info({MyApp.SomeSchema, value}, socket) do
    {:noreply, assign(socket, values: [value | socket.assigns.values])}
  end
end

You can add it into your MyAppWeb module in the live_view part of the __using__ macro to automatically import this function.

defmodule MyAppWeb do
  def live_view do
    quote do
      # ...other code...
      import MyAppWeb.Flash, only: [result_flash: 2]

      unquote(html_helpers())
    end
  end
end

This way all you will need in LiveViews will be |> result_flash(socket).

This is not an extremely complicated change, but a convenience that is nice to have. You can extend it with knowledge and functionalities from [Put flash from anywhere]({{< ref "posts/put_flash_from_anywhere" >}}) or [Subscribe from live components]({{< ref "posts/live_component_subscribe" >}}) to make it work in all places along the application.

Related projects