使用在线将数据从模型/数据库传递到通道

时间:2017-04-21 05:50:48

标签: javascript elixir phoenix-framework phoenix-channels

我有一个我构建的简单聊天应用程序,我希望能够在频道的html页面上的用户名旁边显示用户上传的图像(本地托管)。目前,我正在使用在线状态来跟踪登录频道的用户等。我能够覆盖fetch/2功能,并了解它允许我向{{1}添加几个地图字段带有用户模型数据的符号。

基于每个功能的不同部分的广泛:metas,我可以分辨出来;我的JS层上有IO.inspectingfetch/2和一些console.logging,handle_info/2函数实际上并没有从数据库中获取任何数据,也没有将它分配给{{1} }地图。

这是我当前的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仍为空。

另外,根据文档,查询只应该在连接上运行,以免重载数据库,但每次刷新页面时它似乎运行4-5次。另外需要注意的是,条目中的Users[keys]似乎是一个字符串类型。我不确定这是否重要,我已经尝试从JS层传递一个整数,并使用实际users函数中的user.id来改变它无济于事。

当我检查用户地图时,我得到了这个:

Interger.parse

我的用户[key]返回一个像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]}} 如果我在elixir代码中转换它,{{1}如果我从JS层转换它。

原始%{}输出是(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 –fetch/2以及online_at: 1492764577562 var中我的用户ID或电子邮件的数组。

我在这里失踪的是什么?我知道phx_ref: "OAyzaGE82xc="函数只作为我在:metas通道函数中调用的users函数的回调执行。我也在我的JS层中调用fetch/2并将其映射到我的状态,以便我可以在HTML中生成用户名列表。我只是误解了它是如何工作的,还是有其他更简单的方法我应该这样做?如果您需要查看更多代码,我可以提供更多代码。

编辑:我对这里发生的事情有了更好的理解。我的条目地图实际上是这样的:

Presence.list/1

基本上,用户ID的字符串handle_info/2正被映射到Presence.list地图上。当我尝试使用%{"1" => %{metas: [%{online_at: 1492798247818, phx_ref: "ELHwA+gWF+0="}]}} 函数从地图中取出该密钥时,它无法从数据库中提取任何内容,因为它是一个字符串,但是,当我将其更改为它会抛出一个错误,因为无论出于什么原因,phoenix都期望该键是一个字符串类型。奇怪的是,如果我将"1"metas更改为Map.keys(entries)并尝试使用电子邮件查询数据库,那么它也无法正常工作。尽管数据库中的电子邮件是字符串,id映射期望id映射的字符串键。

我将从头开始重建应用程序的这个频道部分,看看是什么导致了这个问题。然后我会回来看看我是否能够修复错误。

2 个答案:

答案 0 :(得分:0)

您应首先验证条目地图中的密钥。

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]]

注意它强制字符串&#34; 3&#34;到一个整数并允许nil。

然而,地图不会那么友善:

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

因此,在使用entries中的密钥进行数据库查找和映射查找的代码中,它可能会产生不同的结果。

答案 1 :(得分:0)

我已经发现问题与我的fetch/2函数本身没什么关系,相反,它与我在这种情况下实现存在模块和通道有关。基本上,每当有人进入聊天室时,fetch/2函数被调用4次,而使用空列表值[]调用它时,有4次被调用。

显然,您无法使用空列表查询Ecto模型,因此在这种情况下也会抛出错误。我尝试在fetch函数上设置保护来过滤掉空列表调用,但即使查询成功,也不会向我显示我正在寻找的metas地图数据。

另外,另一个主要问题是我的实施或缺乏token的实施。如果我使用令牌加入聊天室而不是metas(也就是用户名),我就不必通过fetch function user map传递用户模型数据。实现之后,我能够成功地将用户模型数据与通道连接起来,并通过JS层显示,最终将其放在客户端上。

无论如何,感谢你的建议。你可能没有回答这个问题(提出错误的问题是我的错),但你确实帮助我实现了目标。并且还为我提供了工具,以便在整个过程中更好地理解框架。

如果/当我还有其他问题时,我会确保在将它们发布到堆栈溢出之前询问正确的问题,这样我就不会浪费时间。