Clarification assign_new in phoenix component

docs says

https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html#assign_new/3-referencing-parent-assigns

By using assign_new in the mount callback of your LiveView, you can instruct LiveView to re-use any assigns set in your Plug pipelines as part of Plug.Conn, avoiding sending additional queries to the database.

current_user is reused but apparently no other assigns in conn

I tried to put a :testvar assign in conn, at the same place where current_user is set, it is ignored by assign_new

the value testvar in conn is seen at first rendering for a fraction of a second, and then it is replaced by the one in assign_new at second rendering

In some cases, there may be data that is shared by your Plug pipelines and your LiveView, such as the :current_user assign.

so what are the cases ?

Assigns in Conn are different to assigns in LiveViews.

The magic behind assign_new is that you can do that on any place where you think a liveview might already have set that and use it as a “default” such as Live Sessions and Phoenix Components.

Iirc LiveBeats uses live sessions that way. Found the link:

yes but here the assign is explicit and from session,

I am talking about an implicit assign from conn

LivViews are rendered twice when users first join your page, there’s a disconnected and a connected render. What are those?

When your user first GET /some-page on your site Phoenix will render the final HTML and send it for your user so he can have it even if their JavaScript is disabled. That’s the disconnected rendering. Since this run on your server entirely it can reuse any assigns coming from plugs that you might have on your pipeline. If the assign :current_user was already there you’d not need to load it from the DB again on your LiveView just because the plug already did that.

After your user sees the HTML rendered from the server and your JavaScript kicks in your LiveView will connect to the WebSocket so it can start rendering again, that’s the connected render. You can verify which render you’re doing by using this function connected/1. The reason your test_var changes is because this second rendering does not go through your plugs therefore it doesn’t have any assigns at first then assign_new kicks in, changes the test_var and then you see the screen rewriting it.


Ive did a little experiment with that

Screen Recording 2022-10-30 at 08.13.33

I’ve created a simple Plug:

defmodule AssignNewExampleWeb.AssignTestVar do
  def init(_) do
    []
  end

  def call(conn, _params) do
    "Im inside the plug now" |> IO.puts()

    conn
    |> Plug.Conn.assign(:test_var, "Im from the Plug")
  end
end

and a simple liveView

defmodule AssignNewExampleWeb.PageLive do
  use AssignNewExampleWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok,
      assign_new(socket, :test_var, fn ->
        "Im running this assign_new. Connected?=#{connected?(socket)}"
        |> IO.puts()

        "Im from PageLive"
      end)
    }
  end

  def render(assigns) do
    if assigns[:test_var] do
      IO.puts("✅ I already have test_var")
    else
      IO.puts("❌ I dont have test_var")
    end

    ~H"""
    <div>
      Here. Test var is: <%= @test_var %>
    </div>
    """
  end
end

From the plug the assign test_var is already fed on the first rendering and only after we are connected we need to run the assign_new. See this commit

Hope this helps!

That ’ s exactly what I have done myself but the question is
why does current_user is retrieved from conn by assign_new and not the same for any other variable in conn.

your example demonstrates that testvar is not retrieve from conn by assign_new.
Only if you explicitly pass it to socket would it be considered already here by assign new (if you came from a patch for instance which does not round trip by liveView )

So is current_user an exception, or else how do you make a variable in conn be detected by assign_new ?

Im not sure I follow the issue. Can you show some code you have?

the problem raises out of this post

I had an assign_new that I thought did not shared current_user from conn but is does.

So I was wondering how to make this happen, how to make another variable be retrieved from conn by assign_new. Or if this is only “hardcoded” for current_user.

of course you can pass variables through session in mount, but then why an exception for current_user ?

that’s what I do not understand

Any assign coming from Plug.Conn.assign should be available out of the box for your render function, it’s not specific for current_user, my example above does that for test_var like you did for testvar.

yes it is, on first render, but then why does assign_new considers it’s not here and triggers it’s function

on the other example I pointed to, the assign_new that fetches current_user (with preload in my case) is not triggered because current_user (regular one with no preload) is already present in conn

so for current_user assign_new is not triggered, but for another variable I see testvar from conn subrepticely, and then replaced by assign_new.
but it should not be replaced by the assign_new version if it was like for current_user

Can you verify if this is triggering only on connected? or if it always trigger?

Is it always replaced, even on disconnected render?

it is triggered when connected? (on second render)
then if I click on a live redirect link it’s ok because current_user with preload is here
but If a full page reload then assign_new considers current_user (with no preload) in conn is already here and assign_new is not triggered

you can run the example at here is the repo GitHub - blset/bg1

see Liveview 0.18.3 bug on component? - #17 by blset

Can you create a repo with the issue you’re pointing towards because I’m not sure I’m following your questions.

Also this thread is starting to feel like a duplicate of the other one

the repo is here GitHub - blset/bg1

sorry if it feels like a duplicate but the common point of the posts is that I would like to know as the docs says if current_user is retrieved by assign_new from conn, it looks like it’s not

in the application register a user, give him a parameter, create a row and then go to rows

on the index page one see clearly the first and second render
on the show page with a buggy component, it crashes on a full page reload but not on a live_redirect from index page

the reasons are clear (on initial render the current_user has no preload) but I don’t see that current_user is retrieved from conn by assign_new as advertised in the docs

also a testvar is here and it’s not retrieved either by assign_new