I think that the second clause will never match because Presence.get_by_key/2
returns a presences()
map that is defined as
presences() :: %{required(String.t()) => %{metas: [map()]}}
so, in the second clause, instead of
%{users: active_users_for_product} ->
we should have
%{metas: [%{users: active_users_for_product}]} ->
this is the complete code
def track_user(pid, product, token) do
user = Accounts.get_user_by_session_token(token)
case Presence.get_by_key(@user_activity_topic, product.name) do
[] ->
Presence.track(
pid,
@user_activity_topic, product.name,
%{users: [%{email: user.email}]}
)
# %{users: active_users_for_product} ->
%{metas: [%{users: active_users_for_product}]} ->
Presence.update(pid, @user_activity_topic, product.name, %{
users: [active_users_for_product | %{email: user.email}] })
end end
I also noticed another little bug with list concatenation: using the |
operator to append the new user to the previous, the list of previous users should be prepended by the map with the new user, not followed by. Instead of
Presence.update(pid, "user_activity", product.name, %{
users: [active_users_for_product | %{email: user.email}] })
should be
Presence.update(pid, "user_activity", product.name, %{
users: [%{email: user.email} | active_users_for_product] })
But now we have the last problem: Presence.update/4
will return {:error, :nopresence}
when trying to add a new user when she/he is viewing the same product page. This because only the socket/PID tracking the presence object can update/modify it, as noticed here. A workaround could be registering the process with a name, as explained in this article.
Besides these errata, your book is fantastic, it explain very well not only LiveView but many other aspect of the E/OTP ecosystem, and it is superbly written, a real joy to read!