Передача данных из модели / базы данных в канал с использованием присутствия

У меня есть простое приложение для чата, которое я построил, и я хочу иметь возможность отображать загруженные пользователем изображения (локально размещенные) рядом с именами пользователей на html-странице канала. В настоящее время я использую присутствие для отслеживания пользователей, которые вошли в канал и т. Д. Мне удалось переопределить fetch/2 с пониманием, что это позволит мне добавить пару полей карты в :metas символ с данными модели пользователя.

Из того, что я могу сказать, основываясь на обширной IO.inspecting различных частей каждой из функций; fetch/2, handle_info/2и некоторые console.logging на моем уровне JS, fetch/2 функция фактически не получает никаких данных из базы данных и не присваивает их :metas карта.

вот мой ток fetch/2 функция:

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

Это в основном копируется прямо из документации. В теории, функция выше должна запросить мою модель пользователя и захватить все пользовательские данные, основанные на User.id это передается ему через карту записей. Users[keys] возвращается как пустой users быть полной картой моей модели пользователя.

Кроме того, согласно документации, запрос должен выполняться только при объединении, чтобы не перегружать БД, но, похоже, он выполняется 4-5 раз при каждом обновлении страницы. Еще одна вещь, которую стоит отметить, это то, что user.id внутри записей, похоже, строковый тип. Я не уверен, если это важно, я попытался передать целое число из слоя JS, а также с помощью Interger.parse от фактического fetch/2 Функция изменить это безрезультатно.

Когда я проверяю карту пользователей, я получаю это:

{"1" => %MyApp.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, 
email: "test@test.com", encrypt_pass: "$pbkdf2-
sha512$160000$ebfY956TgIXhEAF.mqLJAg$QWzBubfeiy4Xrf‌​.EsFiU0jEZAuKvV4ZO5a‌​
8QpeFr817C61DuaNfyo5‌​6WWzj6jak2homCFWAINb‌​PrFtCSXUPWTw", gravatar: %
{file_name: "logo.png", updated_at: #Ecto.DateTime<2017-04-20 22:00:08>}, 
id: 1, inserted_at: ~N[2017-04-20 22:00:09.071000], password: nil, 
updated_at: ~N[2017-04-20 22:00:09.090000]}}

Мои пользователи [ключ] возвращает пустую карту, как это %{} и преобразование ввода в целое число выдает ошибку, (Poison.EncodeError) unable to encode value: {nil, "users"} если я преобразую его внутри кода эликсира, и where: u.id in ^["undefined"], select: {u.id, u} (elixir) lib/enum.ex:1755: Enum."-reduce/3-lists^foldl/2-0-"/3 – если я преобразую его из слоя JS.

Оригинал fetch/2 вывод представляет собой массив с online_at: 1492764577562 а также phx_ref: "OAyzaGE82xc=" в :metas карта и мой идентификатор пользователя или адрес электронной почты в users вар.

Что мне здесь не хватает? Я знаю что fetch/2 Функция выполняется только как обратный вызов Presence.list/1 функция, которую я называю в моем handle_info/2 функция канала Я тоже звоню Presence.list в моем слое JS и сопоставление его с моим присутствием, чтобы я мог создать список имен пользователей в HTML. Я просто неправильно понимаю, как это работает, или есть какой-то другой более простой способ, которым я должен идти об этом? Если вам нужно увидеть больше кода, я могу предоставить больше.

редактировать: я гораздо лучше понимаю, что здесь происходит. моя карта записей на самом деле это:

%{"1" => %{metas: [%{online_at: 1492798247818, phx_ref: "ELHwA+gWF+0="}]}} 

Таким образом, в основном, строка для идентификатора пользователя, "1" отображается на metas карта. Когда я пытаюсь просто взять этот ключ с карты с Map.keys(entries) Функция не может извлечь что-либо из БД, потому что это строка, однако, когда я изменяю ее на целое число со стороны JavaScript, он выдает ошибку, потому что по какой-то причине Феникс ожидает, что этот ключ будет строковым типом, Как ни странно, если я изменю id из id для email и попробуйте запросить базу данных с электронной почтой, она тоже не работает. несмотря на то, что адрес электронной почты в базе данных является строкой и metas карта ожидает ключ строки для entries карта.

Я собираюсь восстановить эту часть приложения с нуля и посмотреть, что вызывает эту проблему. Тогда я вернусь и посмотрю, смогу ли я исправить ошибку.

2 ответа

Решение

Я уже понял, что проблема имеет очень мало общего с моим fetch/2 сама функция, скорее, это было связано с моей реализацией модуля присутствия и канала в этом случае. В основном, fetch/2 функция вызывается 4 раза каждый раз, когда кто-то входит в чат, а два раза из четырех вызывается с пустым значением списка [],

Очевидно, что вы не можете запросить модель Ecto с пустым списком, поэтому в этом случае выдает ошибку. Я попытался установить защиту для функции выборки, чтобы отфильтровать вызовы пустого списка, но это не показывало metas данные карты, которые я искал, даже когда запрос был выполнен успешно.

Кроме того, другой главной проблемой была моя реализация или отсутствие реализации token, Мне не пришлось бы передавать данные модели пользователя через функцию выборки metas карта, если я использовал токен для присоединения к чату, а не просто user (ака просто имя пользователя). После этого я смог успешно связать данные пользовательской модели с каналом и показать их через уровень JS и, в конечном итоге, поместить на клиент.

В любом случае, ребята, спасибо за предложения. Возможно, вы не ответили на вопрос (это была моя вина, что я задал неправильный вопрос), но вы, безусловно, помогли мне добраться туда. А также дал мне инструменты, чтобы сформировать намного лучшее понимание структуры в целом на пути.

Если / когда у меня появятся какие-либо вопросы, я постараюсь задать правильные вопросы, прежде чем публиковать их в переполнение стека, чтобы не тратить время.

Сначала вы должны проверить ключи на карте записей.

ids = Map.keys(entries)
true = Enum.all?(ids, &is_integer/1)

Ecto преобразует строки в целые числа при интерполяции в запрос:

iex(40)> Ecto.Query.from(u in Users, where: u.id in ^[1, 2, "3", nil], select: u.id) |> Repo.all()

выводит следующий журнал отладки:

[debug] QUERY OK source="users" db=0.8ms
SELECT u0."id" FROM "users" AS r0 WHERE (r0."id" = ANY($1)) [[1, 2, 3, nil]]

Обратите внимание, что она привела строку "3" к целому числу и допустила ноль.

Однако карта не будет такой доброй:

iex(42)> users = %{1 => %{name: "joe"}, 2 => %{name: "jill"}}
%{1 => %{name: "joe"}, 2 => %{name: "jill"}}
iex(43)> users["1"]
nil

Так что в коде, где вы используете ключи от entries для поиска в базе данных и поиска на карте это может привести к различным результатам.

Другие вопросы по тегам