polypush135

polypush135

Example of best way to hydrate sessions for LiveView

Going off the example auth blog post where we have a plug helper like so.

# lib/my_app/router.ex
import MyAppWeb.UserAuth

pipeline :browser do
   ...
  plug :fetch_current_user
end

# lib/my_app_web/controllers/user_auth.ex
@doc """
Authenticates the user by looking into the session
and remember me token.
"""
def fetch_current_user(conn, _opts) do
  {user_token, conn} = ensure_user_token(conn)
  user = user_token && Accounts.get_user_by_session_token(user_token)
  assign(conn, :current_user, user)
end

In the context of a LiveView module, I see the user_token in the session on the mount callback.

I have seen the notes about sessions being serialized into strings, should I be concerned about upstream pipelines that adds this usrer_token to the session? When inspecting my session values on the mount I see a binary for the user token.

"user_token" => <<..,, ..., ..., ..., >>

Also, I’ve seen the notes about storing the user id vs the whole user value because of the string serialization.

After some reading, it looks like the past way of setting up the session from the route no longer works. Remove deprecate features · phoenixframework/phoenix_live_view@0020c35 · GitHub

My other question is do I just make another plug that sets the session with the user_id for the socket?
if so I assume I then will need to query for the user via the user id every request for LiveView and auth. Is there a better way?

Marked As Solved

chrismccord

chrismccord

Creator of Phoenix

your second greedy match mount/3 should not be necessary and the fact that you are getting there is definitely the issue. The connected call will include the Plug session , provided you have wired up the session options in your endpoint and csrf token in app.js. Can you post your endpoint? If you are getting here:

# Runs the second time for the js call
def mount(params, session, socket) do
  # Does not show user_token or current_user
  IO.inspect([params, session, socket])

  {:ok, socket}
end

Then it makes sense the current_user is not there, because it was never set. The first clause should have matched, so let’s kill the catch-all and figure out why your plug session isn’t being provided.

Also Liked

chrismccord

chrismccord

Creator of Phoenix

You need to pull the user_token from the session and fetch the user in the same way the plug pipeline does. You can make use of assign_new to avoid fetching on the HTTP request, but you need to fallback to fetching on the connected mount, using the same mechanism that the plug pipeline does:

      def mount(_params, %{"user_token" => user_token}, socket) do
        {:ok, 
          socket 
          |> ...
          |> assign_new(:current_user, fn -> 
            Accounts.get_user_by_session_token(user_token)
         end)}
      end

To avoid duplication in your LVs, you could pull this out into an assign_defaults function that you write to wire up common assigns, like current_user. Make sense?

ChristopheBelpaire

ChristopheBelpaire

Hello,
I wanted to achieve the same kind of behaviour and be able to access to the current_user in my live view assigns.
The best would be able to assign the current_user to the socket assign, but it doesn’t seems to be possible.
The only way I found to achieve this is to inject a mount function, in live :

  def live do
    quote do
      use BrandManagerWeb.LoadUser
      use Phoenix.LiveView, layout: {BrandManagerWeb.LayoutView, "app.html"}
      alias BrandManagerWeb.Router.Helpers, as: Routes
    end
  end
defmodule BrandManagerWeb.LoadUser do
  alias Core.Accounts
  alias Phoenix.LiveView

  defmacro __using__(_opts) do
    quote do
      def mount(params, %{"user_id" => user_id} = session, socket) do
        session = Map.delete(session, "user_id")

        socket =
          LiveView.assign_new(socket, :current_user, fn ->
            manager_id && Accounts.get_user(user_id)
          end)

        mount(params, session, socket)
      end
    end
  end
end

It is working, but it is kind of a hack :wink:

Is there a better way to achieve this ?
Thanks in advance!

sfusato

sfusato

That’s now the default behaviour (all the session is passed and you don’t need to specify the keys):

When a LiveView is rendered, all of the data currently stored in the connection session (see Plug.Conn.get_session/1 ) will be given to the LiveView.

It is also possible to pass additional session information to the LiveView through a session parameter:

# In the router
live "/thermostat", ThermostatLive, session: %{"extra_token" => "foo"}

# In a view
<%= live_render(@conn, AppWeb.ThermostatLive, session: %{"extra_token" => "foo"}) %>

Notice the :session uses string keys as a reminder that session data is serialized and sent to the client. So you should always keep the data in the session to a minimum. I.e. instead of storing a User struct, you should store the “user_id” and load the User when the LiveView mounts.

You could always add a cache for getting the user with a low refresh ttl value.

Where Next?

Popular in Questions Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 127089 1222
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement