Programming Phoenix LiveView B3.0 comments on Chapter 9 (Build a Distributed Dashboard):

P234 Spelling:

“…that sends a message from some other area of you application…” you should be your

P237 Suggestion:

“…The configuration sets the default adapter, PubSub.PG2. This adapter runs on Distributed Erlang––clients across distributed nodes of our app can subscribe to a shared topic and broadcast to that shared topic, because PubSub can directly exchange notifications between servers when configured to use the Phoenix.PubSub.PG2 adapter…”

This could do with more explanation. It assumes a considerable amount of knowledge outside that covered so far in the book. If a reader doesn’t have this additional knowledge, they will not be able to understand what is being said here - which is pretty key to what we’re about to do.

P239 Commentary on send_update/2:

As far as I can see from Elixir docs, there is only a send_update/3 function (where the first parameter is a PID which defaults to self() if not specified and the id: is a component mounted within the live view sending the update). I assume this is what is meant?)

P240 - Suggestion

"…Once send_update/2 is called, the component updates with any new assigns passed as the second argument to send_update/2,…

t took me some time, and reading of the Elixir docs, to realise that we’re not actually sending any meaningful update as part of the second argument, just the id: (which is required by send_update anyway) and that we’re relying on the fact that preload and update will re-query the database and thus pick up the new data.
It might be worth being more explicit about this. At first I was a bit thrown by the fact we didn’t seem to be passing anything of interest - and it wasn’t clear to me that we could have send another assign as an informational payload, but we chose not to do so as in this particular case, it is unnecessary.

P240 Suggestion about the age_group filter code snippet and explanation:

“…That’s the age_group filter…”

he assign_age_group_filter(socket) remains unchanged.

We introduce a new assign_age_group_filter( %{assigns: %{age_group_filter: age_group_filter}} = socket)

It’s not clear whether we are supposed to delete the other assign_age_group_filter(socket, age_group_filter). I established that we’re not - the code doesn’t compile if we do.

It would be useful to make clear that all we are doing here is introducing a new version of assign_age_group_filter (i.e. assign_age_group_filter( %{assigns: %{age_group_filter: age_group_filter}} = socket) ) and that the two existing versions remain unchanged.

P241 Suggestion:

“Next up, we’ll build a section into our dashboard to track user activity…”

Before we move on, it might be useful to show a way of testing this. Can we log in twice as userA and userB, have UserA looking at the dashboard and userB submitting a survey?

From here on, I will refer to things being “in the code”. By “the code” I mean the code in the zipfile (downloaded today, 8th April 2021 at 09:16 UK time) for the “interactive dashboard” folder. I have assumed this code is the “final” interactive dashboard code and as such, should not have any of the “distributed dashboard” code in it - so we can use it as a starting point to “code along” with the Distributed Dashboard chapter. As can be seen from the comments below, that is not always the case. Some, but not all Distributed Dashboard code was present in this Interactive Dashboard code.

P243 Mix up in the code in the zip file

“…So far, there’s not much happening, but let’s call out the details…”

There appears to be much more than this in the code for the interactive dashboard chapter (i.e. which should be the starting code for this chapter). Specifically, the track_user function appears in the code, whereas we’re told to “add” it to the code many pages beyond here on P247

P244 - lib/pento/application.ex module is already present in the code

P244 Mount/3 code is already present

."…So, we’ll update our mount/3 function in lib/pento_web/live/product_live/show.ex to grab the token from the session and store it in socket assigns, like this:…"

It was already there

P245 Handle_params multiple comments:

alias PentoWeb.Presence 
alias Pento.Accounts

are not in the code (correctly)

product = Catalog.get_product!(id)
maybe_track_user(product, socket)

Similarly, these two lines - Product and maybe_track_product - are correctly not in the code

|> assign(:product, product)}

appeared in the code as:

assign(:product, Catalog.get_product!(id))

Finally, neither of the maybe_track_user definitions were in the code

P247 - track_user/3 is already in the code

P247 error:

"…Notice that we’ve also moved the call to Accounts.get_user_session_by_token/1 into this new Presence module function…

It’s actually Accounts.get_user_by_session_token(token) in the code

P248 maybe_track_user multiple comments:

%{assigns: %{live_action: :show, user_token: user_token}}

VSCode syntax checking was unhappy with this, complaining for if connected?(socket) that socket was undefined.

changing the %{assigns: … line to:

%{assigns: %{live_action: :show, user_token: user_token}} = socket

stopped it complaining

Presence.track_user(self(), product, socket.assigns.user_token)

Needed to remove the socket.assigns prefix to stop VSCode complaining about unused user_token (in the %{assigns…. line above)

def maybe_track_user(product, socket), do: nil

VSCode complained that product and socket were unused. They needed underscores.

At the end of this, the code I ended up with is:

def maybe_track_user(
product,
%{assigns: %{live_action: :show, user_token: user_token}} = socket
) do
if connected?(socket) do
Presence.track_user(self(), product, user_token)
end
end

def maybe_track_user(_product, _socket), do: nil

P250 - Browser sessions:

“…Open a few different browser sessions for different users…”

In my case, on MacOS, these needed to be entirely different browsers (i.e. Safari, Chrome, Firefox) or incognito sessions within chrome.

Otherwise, it was not possible to log in as different users.

Hi @asibbald! Thanks for your questions and comments. I’ll take them one at a time:

P234 Spelling:
“…that sends a message from some other area of you application…” you should be your

Yep! Will fix.


P237 Suggestion:
“…The configuration sets the default adapter, PubSub.PG2. This adapter runs on Distributed Erlang––clients across distributed nodes of our app can subscribe to a shared topic and broadcast to that shared topic, because PubSub can directly exchange notifications between servers when configured to use the Phoenix.PubSub.PG2 adapter…”
This could do with more explanation. It assumes a considerable amount of knowledge outside that covered so far in the book. If a reader doesn’t have this additional knowledge, they will not be able to understand what is being said here - which is pretty key to what we’re about to do.

Which part of this explanation felt unclear to you? The intended take-away here is: By using the PG2 adapter, your code will work even if you deploy your application in a distributed manner". This is what we mean by:

clients across distributed nodes of our app can subscribe to a shared topic and broadcast to that shared topic, because PubSub can directly exchange notifications between servers when configured to use the Phoenix.PubSub.PG2 adapter

It’s not important to understand the mechanics of the PG2 adapter or Distributed Erlang beyond that, and I don’t feel that a lack of that deeper understanding will prevent the reader from building out the feature in this section.


P239 Commentary on send_update/2:
As far as I can see from Elixir docs, there is only a send_update/3 function

Correct, that should read send_update/3, will fix for the next Beta :rocket:


P240 - Suggestion
"…Once send_update/2 is called, the component updates with any new assigns passed as the second argument to send_update/2,…

Thanks for sharing your thinking here! It’s always helpful to see how readers are grappling with the concepts. I think I’m going to leave that prose alone for now and see if others raise similar points before changing it.


P240 Suggestion about the age_group filter code snippet and explanation:

I’m going to change this line:

So, we’ll implement new function heads for these reducers that enact this logic:

To:

So, we’ll implement additional function heads for these reducers that contain this logic:


Before we move on, it might be useful to show a way of testing this. Can we log in twice as userA and userB, have UserA looking at the dashboard and userB submitting a survey?

Yep I think this kind of suggested demo would be great to see. Will include something like that in the next Beta :grinning_face_with_smiling_eyes:


There appears to be much more than this in the code for the interactive dashboard chapter (i.e. which should be the starting code for this chapter). Specifically

I’ll review this code and make any necessary fixes for the next Beta.


P250 - Browser sessions:
In my case, on MacOS, these needed to be entirely different browsers (i.e. Safari, Chrome, Firefox) or incognito sessions within chrome.
Otherwise, it was not possible to log in as different users.

You should be able to open up a regular (let’s say) Chrome window and an incognito window to create “different browser sessions”. However, the term “different browser sessions” is left a bit vague so that the reader can do whatever works for them.