Accessing socket's assigns in a helper function results to `%Phoenix.LiveView.Socket.AssignsNotInSocket{}`

Hello. I’m new to LiveView.

In a live template I want to call a helper function to derive some state.

<%= if allowed_to_make_foo?(@socket) do %>
defp allowed_to_make_foo?(socket) do
  last_foo = socket.assigns.last_foo
  current_user = socket.assigns.current_user
  is_admin = socket.assigns.is_admin

  !last_foo || current_user.id == last_foo.user_id || is_admin
end

The problem is that I cannot access :assigns fields from the socket:

:assigns is equal to %Phoenix.LiveView.Socket.AssignsNotInSocket{}.

I’d find it a pity to add a new state variable (:is_allowed_to_make_foo) to compute this derived value; I’d need to keep that new state in sync every time I edit one of the variables.
Another option is to add the logic in the live template each time (!@last_foo || @current_user.id == @last_foo.user_id || @is_admin) but that is cumbersome.

1 Like

I’m also an elixir noob but – it may be better to derive your state off another assigns property. Consider that all your assigns in the template are accessed the same way:

socket |> assigns(user: %{})

gives you @user.

Sadly the remedy may be along these lines. Your error implies that the syntax @socket triggers a pattern-match for the property socket in your socket.assigns, which is not the case. Hence the suggestion to generate an initial assign property, which you can pass into your allowed_to_make_foo? helper.

Hope this allows_you_to_make_foo!

IIRC You can pass assigns instead of socket.

I do not think this (adding a state which is derived from multiple state variables) is a best practice because then you have to keep state in sync and it’s a source of bugs.

No, @socket exists. It’s available by default in live templates. It’s not taken from :assigns.

I tried @assigns but then I have the error:

assign @assigns not available in eex template.

Also tried to pass @socket.assigns from the template, but again :assigns is %Phoenix.LiveView.Socket.AssignsNotInSocket{}.

1 Like

Not @assigns, but assigns…

2 Likes

that works!