elixirphoenix-frameworkphoenix-live-view

current_user is not available on the socket, even though it's assigned through `on_mount HealthTrackerWeb.UserLiveAuth`


I've built a simple CRUD app that can be used to track health metrics like Weight.

I've followed the official guide to access current_user from the socket. That allowed me to reach out to socket.assigns.current_user.id whenever I need. But unfortunately the socket does not contain the current_user when I press Edit within the Show modal.

This view http://localhost:4000/weights/27/show/edit edit action on show modal

This is from the logs:

[debug] HANDLE EVENT "save" in HealthTrackerWeb.WeightLive.Show
  Component: HealthTrackerWeb.WeightLive.FormComponent
  Parameters: %{"weight" => %{"weight" => "88888.1"}}
from show edit
socket:


#Phoenix.LiveView.Socket<
  id: "phx-F36nLW9MP7w9NQZk",
  endpoint: HealthTrackerWeb.Endpoint,
  view: HealthTrackerWeb.WeightLive.Show,
  parent_pid: nil,
  root_pid: #PID<0.2019.0>,
  router: HealthTrackerWeb.Router,
  assigns: %{
    __changed__: %{},
    action: :edit,
    flash: %{},
    form: %Phoenix.HTML.Form{
      source: #Ecto.Changeset<action: :validate, changes: %{}, errors: [],
       data: #HealthTracker.HealthStats.Weight<>, valid?: true>,
      impl: Phoenix.HTML.FormData.Ecto.Changeset,
      id: "weight",
      name: "weight",
      data: %HealthTracker.HealthStats.Weight{
        __meta__: #Ecto.Schema.Metadata<:loaded, "weights">,
        id: 27,
        weight: 88888.1,
        user_id: 1,
        inserted_at: ~N[2023-08-26 04:35:49],
        updated_at: ~N[2023-08-26 04:35:58]
      },
      hidden: [id: 27],
      params: %{"weight" => "88888.1"},
      errors: [],
      options: [method: "put"],
      index: nil,
      action: nil
    },
    id: 27,
    myself: %Phoenix.LiveComponent.CID{cid: 1},
    patch: "/weights/27",
    title: "Edit Weight",
    weight: %HealthTracker.HealthStats.Weight{
      __meta__: #Ecto.Schema.Metadata<:loaded, "weights">,
      id: 27,
      weight: 88888.1,
      user_id: 1,
      inserted_at: ~N[2023-08-26 04:35:49],
      updated_at: ~N[2023-08-26 04:35:58]
    }
  },
[error] GenServer #PID<0.2019.0> terminating
** (KeyError) key :current_user not found in: %{__changed__: %{}, action: :edit, flash: %{}, form: %Phoenix.HTML.Form{source: #Ecto.Changeset<action: :validate, changes: %{}, errors: [], data: #HealthTracker.Health
Stats.Weight<>, valid?: true>, impl: Phoenix.HTML.FormData.Ecto.Changeset, id: "weight", name: "weight", data: %HealthTracker.HealthStats.Weight{__meta__: #Ecto.Schema.Metadata<:loaded, "weights">, id: 27, weight:
88888.1, user_id: 1, inserted_at: ~N[2023-08-26 04:35:49], updated_at: ~N[2023-08-26 04:35:58]}, hidden: [id: 27], params: %{"weight" => "88888.1"}, errors: [], options: [method: "put"], index: nil, action: nil}, i
d: 27, myself: %Phoenix.LiveComponent.CID{cid: 1}, patch: "/weights/27", title: "Edit Weight", weight: %HealthTracker.HealthStats.Weight{__meta__: #Ecto.Schema.Metadata<:loaded, "weights">, id: 27, weight: 88888.1,
 user_id: 1, inserted_at: ~N[2023-08-26 04:35:49], updated_at: ~N[2023-08-26 04:35:58]}}
    (health_tracker 0.1.0) lib/health_tracker_web/live/weight_live/form_component.ex:57: HealthTrackerWeb.WeightLive.FormComponent.handle_event/3
    (phoenix_live_view 0.19.5) lib/phoenix_live_view/channel.ex:630: anonymous fn/4 in Phoenix.LiveView.Channel.inner_component_handle_event/4
    (telemetry 1.2.1) /Users/martins/Work/Elixir/health_tracker/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
    (phoenix_live_view 0.19.5) lib/phoenix_live_view/diff.ex:204: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 0.19.5) lib/phoenix_live_view/channel.ex:553: Phoenix.LiveView.Channel.component_handle_event/6
    (stdlib 4.3) gen_server.erl:1123: :gen_server.try_dispatch/4
    (stdlib 4.3) gen_server.erl:1200: :gen_server.handle_msg/6
    (stdlib 4.3) proc_lib.erl:250: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F36nLW9MP7w9NQZk", event: "event", payload: %{"cid" => 1, "event" => "save", "type" => "form", "value" => "weight%5Bweight%5D=88888.1"}, ref: "32", join_ref: "10
"}

[debug] MOUNT HealthTrackerWeb.WeightLive.Show
  Parameters: %{"id" => "27"}
  Session: %{"_csrf_token" => "BVgDB44u3_rdNtmnVSmgDpcq", "live_socket_id" => "users_sessions:J5U-KzfYHgC1dspOxhvXVQcGVtH4DjIl19_-Tz8NXMY=", "user_token" => <<39, 149, 62, 43, 55, 216, 30, 0, 181, 118, 202, 78, 198
, 27, 215, 85, 7, 6, 86, 209, 248, 14, 50, 37, 215, 223, 254, 79, 63, 13, 92, 198>>}
[debug] QUERY OK source="users_tokens" db=0.5ms idle=815.7ms
SELECT u1."id", u1."email", u1."hashed_password", u1."confirmed_at", u1."inserted_at", u1."updated_at" FROM "users_tokens" AS u0 INNER JOIN "users" AS u1 ON u1."id" = u0."user_id" WHERE ((u0."token" = $1) AND (u0."
context" = $2)) AND (u0."inserted_at" > $3::timestamp + (-(60)::numeric * interval '1 day')) [<<39, 149, 62, 43, 55, 216, 30, 0, 181, 118, 202, 78, 198, 27, 215, 85, 7, 6, 86, 209, 248, 14, 50, 37, 215, 223, 254, 7
9, 63, 13, 92, 198>>, "session", ~U[2023-08-26 05:35:40.069525Z]]
↳ Phoenix.LiveView.Utils.assign_new/3, at: lib/phoenix_live_view/utils.ex:79



 ITS RUNNING



UserLiveAuth.on_mount/4: socket:
#Phoenix.LiveView.Socket<
  id: "phx-F36nLW9MP7w9NQZk",
  endpoint: HealthTrackerWeb.Endpoint,
  view: HealthTrackerWeb.WeightLive.Show,
  parent_pid: nil,
  root_pid: #PID<0.2032.0>,
  router: HealthTrackerWeb.Router,
  assigns: %{
    __changed__: %{current_user: true},
    current_user: #HealthTracker.Accounts.User<
      __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
      id: 1,
      email: "martin@stabenfeldt.net",
      confirmed_at: nil,
      inserted_at: ~N[2023-08-01 06:30:14],
      updated_at: ~N[2023-08-01 06:30:14],
      ...
    >,
    flash: %{},
    live_action: :edit
  },
  transport_pid: #PID<0.2013.0>,
  ...

I don't understand why the current_user is assigned to the socket by on_mount(), but not available when I trigger save from the modal.

The ID of the socket that has current_user assigned is the same ID as the socket that DOES NOT have current_user assigned.

Please see my code at https://github.com/stabenfeldt/HealthTracker


Solution

  • In the modal in the show.html.heex is where the assigns is overwritten so just adding it there is enough(row 22):

    I guess it's described in the docs, but now I learned that assigns to live components must be passed in as shown in the photos.

    enter image description here