2017-04-21 22 views
0

我有一個簡單的聊天應用程序,我希望能夠在頻道的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: "[email protected]", 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"}如果我將它從JS層轉換成。

原來fetch/2輸出爲online_at: 1492764577562phx_ref: "OAyzaGE82xc=":metas地圖在users VAR的數組和我的用戶ID或電子郵件。

這是什麼,我在這裏失蹤?我知道fetch/2函數只是作爲回調函數,我在調用handle_info/2通道函數中調用Presence.list/1函數。我還在我的JS層中調用Presence.list,並將其映射到我的存在,以便我可以在HTML中生成用戶名列表。我只是誤解了這是如何工作的,還是有其他更簡單的方法,我應該繼續這樣做?如果您需要查看更多代碼,我可以提供更多代碼。

編輯:我對這裏發生的事情有了更好的理解。我的實體的映射表實際上是這樣的:

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

所以基本上,用戶ID字符串,"1"被映射到metas地圖。當我試圖用Map.keys(entries)函數將該鍵從地圖中取出時,它不能從數據庫中取出任何東西,因爲它是一個字符串,但是,當我將它從JavaScript端更改爲整數時,它將引發錯誤,因爲無論出於什麼原因鳳凰期待該鍵是一個字符串類型。奇怪的是,如果我將idid更改爲email並嘗試使用電子郵件查詢數據庫,它也不起作用。儘管數據庫中的電子郵件地址是字符串,並且metas地圖期望地圖的entries字符串鍵。

我打算從頭開始重建應用程序的這個頻道部分,看看是什麼導致了這個問題。然後我會回來看看我是否能夠解決這個錯誤。

+0

你可以發佈'IO的輸出。在查詢運行後檢查'users'和這個'fetch'函數的返回值? – Dogbert

+0

你說每次刷新頁面時都會調用它。你正在瀏覽器重新加載?如果是這樣,那麼這會拋棄你的頻道並打開一個新頻道,導致在線更新。我還發現,當有人出現變化時,會有很多狀態更新發生。另外,檢查你的'for'理解的關鍵。你可能會得到一個字符串,並且你的用戶id可能是一個整數(除非你在schema中使用二進制ID) –

+0

'{「1」=>%MyApp.User {__ meta__:#Ecto.Schema.Metadata < :加載, 「用戶」>, 電子郵件: 「[email protected]」, encrypt_pass: 「$ PBKDF2-SHA512 $ 160000 $ ebfY956TgIXhEAF.mqLJAg $ QWzBubfeiy4Xrf.EsFiU0jEZAuKvV4ZO5a8QpeFr817C61DuaNfyo56WWzj6jak2homCFWAINbPrFtCSXUPWTw」, 的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:00 09.071000],密碼:無, updated_at :〜N [2017-04-20 22:00:00 09.090000]}}'這是用戶檢查,這裏是用戶[鍵]檢查。 '%{}' – Abeltensor

回答

0

我已經發現這個問題與我的fetch/2函數本身很少有關係,而是與我在這種情況下實現存在模塊和通道有關。基本上,fetch/2功能在每次有人進入聊天室時被調用4次,而在四次調用中被調用的空值列表值爲[]

很明顯,你不能用一個空列表查詢一個Ecto模型,所以它也會在這種情況下拋出一個錯誤。我試圖在抓取函數上放置警衛以過濾掉空的列表調用,但它不會顯示我查找的地圖數據,即使查詢成功。

另外,另一個主要問題是我的實施或缺少實施token。如果我使用令牌加入聊天室而不是僅僅使用user(又名只是一個用戶名),我不必通過獲取函數metas來傳遞用戶模型數據。做完這個實現之後,我能夠成功地將用戶模型數據與頻道連接起來,並通過JS層顯示出來,最終將其放到客戶端。

反正大家,謝謝你的建議。你可能沒有回答這個問題(這是錯誤的提出錯誤的問題),但你肯定幫助我到達那裏。同時也爲我提供了一些工具,用於在途中更好地理解框架。

如果/當我還有任何問題時,我會確保在發佈堆棧溢出之前詢問正確的問題,這樣我就不會浪費時間。

0

您應該首先在條目映射中驗證密鑰。

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

外生將插值到查詢時字符串轉換爲整數:

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密鑰數據庫查詢和地圖查詢的代碼,它可以產生不同的結果。

+0

我試試這個,然後回覆你。 – Abeltensor

相關問題