2

I want to be able to pass user meta data through the :meta map in phoenix presence to access it from the JavaScript side. More specifically, I want to be able to push image file paths (strings) and have them associated with each user in my presence list. The documentation gives this example for overriding the fetch/2 function to add User model data into the :meta map:

def fetch(_topic, entries) do
  query =
    from u in User,
      where: u.id in ^Map.keys(entries),
      select: {u.id, u}

  users = query |> Repo.all |> Enum.into(%{})

  for {key, %{metas: metas}} <- entries, into: %{} do
    {key, %{metas: metas, user: users[key]}}
  end
end

However, when I make the appropriate changes for my User Model, I get errors regarding the variable u and the from/2 function as well as cannot use ^Map.keys(entries) outside of match clauses.

I went looking for examples of people trying to do similar things and was unable to find anything on github that is similar to what I am attempting here.

Anyone have any idea how I can go about restructuring the fetch/2 function so that it will work properly? I have a basic user model with 3 fields, email, password, and icon/avatar image.

Alvin Lindstam
  • 3,094
  • 16
  • 28
Abeltensor
  • 132
  • 1
  • 10
  • Try `require Ecto.Query` at the top of your file. Your errors are typical with those I see when I have not required the file. Also make sure you have imported `Ecto.Query` – Steve Pallen Apr 20 '17 at 23:59
  • Edit: naw, that didn't change the error codes. Im still getting the `warning: variable "u" does not exist and is being expanded to "u()", please use parentheses to remove the ambiguity or change the variable name` as the main warning and the others if i type it manually into the repl, even after requiring Ecto.Query and my User Model. – Abeltensor Apr 21 '17 at 02:41
  • `from` is an Ecto.Query macro. You don't have to do this in controllers and models because its already setup in web.ex when you do `use MyApp.Web, :controller` for example. – Steve Pallen Apr 21 '17 at 02:43
  • It worked with `import Ecto.Query`. require does not work with out actually specifying that from is specifically from the query module it seems. – Abeltensor Apr 21 '17 at 02:52
  • Ok, I'll post an answer so others can see that its answered – Steve Pallen Apr 21 '17 at 02:57
  • thank you for pointing me the the right direction. – Abeltensor Apr 21 '17 at 03:02
  • I'll give you another tip. Remember the error message. It will likely not be the last time you see this error. – Steve Pallen Apr 21 '17 at 03:08
  • Ill keep that in mind. Im currently battling with something similar haha.. Ahh well, thats why its called learning a learning experience I suppose. – Abeltensor Apr 21 '17 at 05:23
  • Have you joined he Elixir slack channel? Great resource. I'm around a lot @smpallen99 – Steve Pallen Apr 21 '17 at 05:33
  • I have been meaning to, just haven't gotten around to it yet. – Abeltensor Apr 21 '17 at 05:51

2 Answers2

1

I found out what my problem is. Basically, the metas map in my application is not always populated with the value that I want it to be. In this case, it doesn't always have the user.id inside of it. Apparently, when a user joins the channel, the fetch function is called at least 4 times. If I inspect the fetch function's entries map after running Map.keys on it, it returns:

["1"]
["1"]
[]
[]

So basically in two out of the four instances where the fetch function is being called, my channel app is returning 2 empty values for the key and when those empty values are put into the query it causes an error.

Unfortunately, this means that there is an error some where else in the application that causes this empty value to be passed to my fetch function; most likely in the JavaScript or my channel modules.

I'm going to have to rebuild this app from scratch, so I guess that means this question is closed. Alternatively, I could put in some error handling in the form of a guard or pattern matching statement to protect against these empty values, but I think it would be better in the long run if I just restart.

Abeltensor
  • 132
  • 1
  • 10
0

You need to import Ecto.Query to use the from macro. This is done in your web.ex file so when you use MyApp.Web, :controller, you have it imported through the quote block in web.ex. However, you need to do this manually in other modules.

Add the following to the top of your presence module like this

defmodule MyApp.Presence do
  use Phoenix.Presence, otp_app: :my_app,
                        pubsub_server: MyApp.PubSub
  import Ecto.Query
  # ...
end
Steve Pallen
  • 4,417
  • 16
  • 33