我有一个我构建的简单聊天应用程序,我希望能够在频道的html页面上的用户名旁边显示用户上传的图像(本地托管)。目前,我正在使用在线状态来跟踪登录频道的用户等。我能够覆盖fetch/2
功能,并了解它允许我向{{1}添加几个地图字段带有用户模型数据的符号。
基于每个功能的不同部分的广泛:metas
,我可以分辨出来;我的JS层上有IO.inspecting
,fetch/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
8QpeFr817C61DuaNfyo56WWzj6jak2homCFWAINbPrFtCSXUPWTw", 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
映射的字符串键。
我将从头开始重建应用程序的这个频道部分,看看是什么导致了这个问题。然后我会回来看看我是否能够修复错误。
答案 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层显示,最终将其放在客户端上。
无论如何,感谢你的建议。你可能没有回答这个问题(提出错误的问题是我的错),但你确实帮助我实现了目标。并且还为我提供了工具,以便在整个过程中更好地理解框架。
如果/当我还有其他问题时,我会确保在将它们发布到堆栈溢出之前询问正确的问题,这样我就不会浪费时间。