Fix error handling and actor access in MemberLive.Index

Replace bang calls with proper error handling and use current_actor/1
helper for consistent actor access.
This commit is contained in:
Moritz 2026-01-09 05:26:11 +01:00
parent 145a76348c
commit 351eac4c02
Signed by: moritz
GPG key ID: 1020A035E5DD0824

View file

@ -31,6 +31,7 @@ defmodule MvWeb.MemberLive.Index do
require Ash.Query
import Ash.Expr
import MvWeb.LiveHelpers, only: [current_actor: 1]
alias Mv.Membership
alias MvWeb.Helpers.DateFormatter
@ -60,7 +61,7 @@ defmodule MvWeb.MemberLive.Index do
# Note: Using Ash.read! (bang version) - errors will be handled by Phoenix LiveView
# and result in a 500 error page. This is appropriate for LiveViews where errors
# should be visible to the user rather than silently failing.
actor = socket.assigns[:current_user]
actor = current_actor(socket)
custom_fields_visible =
Mv.Membership.CustomField
@ -134,14 +135,41 @@ defmodule MvWeb.MemberLive.Index do
"""
@impl true
def handle_event("delete", %{"id" => id}, socket) do
# Note: Using bang versions (!) - errors will be handled by Phoenix LiveView
# This ensures users see error messages if deletion fails (e.g., permission denied)
actor = socket.assigns[:current_user]
member = Ash.get!(Mv.Membership.Member, id, actor: actor)
Ash.destroy!(member, actor: actor)
actor = current_actor(socket)
updated_members = Enum.reject(socket.assigns.members, &(&1.id == id))
{:noreply, assign(socket, :members, updated_members)}
case Ash.get(Mv.Membership.Member, id, actor: actor) do
{:ok, member} ->
case Ash.destroy(member, actor: actor) do
:ok ->
updated_members = Enum.reject(socket.assigns.members, &(&1.id == id))
{:noreply,
socket
|> assign(:members, updated_members)
|> put_flash(:info, gettext("Member deleted successfully"))}
{:error, %Ash.Error.Forbidden{}} ->
{:noreply,
put_flash(
socket,
:error,
gettext("You do not have permission to delete this member")
)}
{:error, error} ->
{:noreply, put_flash(socket, :error, format_error(error))}
end
{:error, %Ash.Error.Query.NotFound{}} ->
{:noreply, put_flash(socket, :error, gettext("Member not found"))}
{:error, %Ash.Error.Forbidden{} = _error} ->
{:noreply,
put_flash(socket, :error, gettext("You do not have permission to access this member"))}
{:error, error} ->
{:noreply, put_flash(socket, :error, format_error(error))}
end
end
@impl true
@ -241,6 +269,24 @@ defmodule MvWeb.MemberLive.Index do
end
end
# Helper to format errors for display
defp format_error(%Ash.Error.Invalid{errors: errors}) do
error_messages =
Enum.map(errors, fn error ->
case error do
%{field: field, message: message} -> "#{field}: #{message}"
%{message: message} -> message
_ -> inspect(error)
end
end)
Enum.join(error_messages, ", ")
end
defp format_error(error) do
inspect(error)
end
# -----------------------------------------------------------------
# Handle Infos from Child Components
# -----------------------------------------------------------------
@ -683,7 +729,7 @@ defmodule MvWeb.MemberLive.Index do
# Note: Using Ash.read! - errors will be handled by Phoenix LiveView
# This is appropriate for data loading in LiveViews
actor = socket.assigns[:current_user]
actor = current_actor(socket)
members = Ash.read!(query, actor: actor)
# Custom field values are already filtered at the database level in load_custom_field_values/2