我有一个简单的聊天应用程序,我希望能够在频道的HTML页面上的用户名旁边显示用户上传的图像(本地托管(。当前,我正在使用存在来跟踪登录到频道等的用户。我能够覆盖fetch/2
功能,以了解它可以让我在:metas
符号中使用用户模型数据添加几个MAP字段。
我可以根据每个功能的不同部分的广泛IO.inspecting
所说的;fetch/2
,handle_info/2
和一些控制台。在我的JS层上插入,fetch/2
函数实际上并未从数据库中获取任何数据,也没有将其分配给:metas
MAP。
这是我当前的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
是我用户模型的完整地图,但Users[keys]
还是空的。
此外,根据文档,查询只能在加入上运行,以免超载DB,但每次我刷新页面时似乎都会运行4-5次。要注意的另一件事是,条目内部的user.id
似乎是字符串类型。我不确定这是否重要,我尝试从JS层传递整数,并使用实际fetch/2
函数中的Interger.parse
将其更改为无用。
当我检查用户地图时,我会得到:
{"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 Code内部,则(Poison.EncodeError) unable to encode value: {nil, "users"}
,如果我从JS层转换了where: u.id in ^["undefined"], select: {u.id, u} (elixir) lib/enum.ex:1755: Enum."-reduce/3-lists^foldl/2-0-"/3 –
,则CC_17。
原始fetch/2
输出是:metas
中的online_at: 1492764577562
和phx_ref: "OAyzaGE82xc="
的数组,在users
VAR中我的用户ID或电子邮件或电子邮件。
我在这里缺少什么?我知道fetch/2
功能仅作为对Presence.list/1
函数的回调执行,我在handle_info/2
Channel函数中调用该功能。我还在我的JS层中调用Presence.list
并将其映射到我的存在中,以便可以在HTML中产生用户名列表。我只是误解了这是如何工作的,还是还有其他一些更简单的方法?如果您需要查看更多代码,我可以提供更多。
编辑:我对这里发生的事情有更好的了解。我的条目地图实际上是:
%{"1" => %{metas: [%{online_at: 1492798247818, phx_ref: "ELHwA+gWF+0="}]}}
基本上,用户ID的字符串映射到metas
地图上。当我尝试使用Map.keys(entries)
函数将该键从地图中取出时,它无法从DB中拉出任何内容,因为它是一个字符串,但是,当我将其更改为JavaScript端的整数时,它会抛出一个错误,因为无论出于何种原因,Phoenix都期望该键是字符串类型。奇怪的是,如果我将id
从id
更改为email
,并尝试通过电子邮件查询DB,也无法正常工作。尽管数据库中的电子邮件是字符串,而metas
地图期望entries
地图的字符串密钥。
我将从头开始重建该频道的一部分,并查看导致此问题的原因。然后,我会回来看看是否能够解决错误。
您应该先验证条目中的键。
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
的键进行数据库查找和地图查找的代码中,它可能会产生不同的结果。
我已经弄清楚了这个问题与我的fetch/2
功能本身无关,而是与我在这种情况下的实现模块和渠道有关。基本上,每当有人进入聊天室时,fetch/2
功能被称为4次,而在四次中有两个被称为空名单值[]
。
显然,您无法查询具有空列表的eTeco模型,因此在这种情况下也丢了错误。我尝试将护罩放在获取功能上以滤除空列表调用,但它也不会向我展示我正在寻找的metas
地图数据,即使查询成功了。
此外,另一个主要问题是我的实施或缺乏token
的实现。如果我使用令牌来加入聊天室,而不是user
(又称一个用户名(,则我不必通过Fetch函数metas
地图传递用户模型数据。实现这一实现后,我能够成功地将用户模型数据与频道连接并通过JS层显示,并最终将其放在客户端上。
无论如何,谢谢您的建议。您可能没有回答这个问题(这是我提出错误的问题的错(,但是您当然可以帮助我到达那里。还为我提供了对一般框架的更好理解的工具。
如果/当我还有其他问题时,我将确保在将它们发布到堆叠溢出之前,请问我要问正确的问题,这样我就不会浪费时间。