【问题标题】:Cannot save chat messages from Elixir to PostgreSQL无法将聊天消息从 Elixir 保存到 PostgreSQL
【发布时间】:2020-12-05 04:51:05
【问题描述】:

重新加载时,我似乎无法将任何消息持久化到数据库中。

它不显示任何错误消息。

为代码添加的链接。

room_channel.ex

defmodule Chat.RoomChannel do
  use Phoenix.Channel
  alias Chat.Presence
  alias Chat.Repo
  alias Chat.User
  alias Chat.Message

  def join("room", payload, socket) do
    if authorized?(payload) do
      send(self(), :after_join)
      {:ok, socket}
    else
      {:error, %{reason: "unauthorized"}}
    end
  end

  def handle_in("new_messages", payload, socket) do
    spawn(fn -> save_message(payload) end)
    user = Repo.get(User, socket.assigns.user_id)
    broadcast! socket, "new_messages", %{user: user.name, message: payload["message"]}
    {:noreply, socket}
  end

  def handle_info(:after_join, socket) do
    Message.recent_messages()
    |> Enum.each(fn msg -> push(socket, "new_messages", format_msg(msg)) end)
    user = Repo.get(User, socket.assigns.user_id)
    {:ok, _} = Presence.track(socket, user.name, %{
      online_at: inspect(System.system_time(:seconds))
      })
    push socket, "presence_state", Presence.list(socket)
    {:noreply, socket}
  end

  defp format_msg(msg) do
    %{
      name: msg.name,
      message: msg.message
    }
  end

  defp save_message(message) do
    Message.changeset(%Message{}, message) |> Repo.insert
  end

  defp authorized?(_payload) do
    true
  end
end

message.ex

defmodule Chat.Message do
  use Ecto.Schema
  import Ecto.Changeset

  schema "messages" do
    field :name, :string
    field :message, :string

    timestamps()
  end

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:name, :message])
    |> validate_required([:name, :message])
  end

  def recent_messages(limit \\ 10) do
    Chat.Repo.all(Chat.Message, limit: limit)
  end
end

mix.exs

defp deps do
    [{:phoenix, "~> 1.2.5"},
     {:phoenix_pubsub, "~> 1.0"},
     {:phoenix_ecto, "~> 3.0"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 2.6"},
     {:phoenix_live_reload, "~> 1.0", only: :dev},
     {:gettext, "~> 0.11"},
     {:cowboy, "~> 1.0"},
     {:coherence, "~> 0.3"}]
end
Elixir 1.11.2 (compiled with Erlang/OTP 23)
postgres (PostgreSQL) 13.0

我认为问题出在 room_channel.ex 中的 handle_in 函数上

spawn(fn -> save_message(payload) end)

任何指向正确方向的线索?

【问题讨论】:

  • 如果您通过删除spawn 并只执行save_message(payload) 来同步保存消息会发生什么?此外,您可能希望在 save_message 函数中处理无效的变更集——在尝试插入之前检查变更集是否有效。
  • 仅使用 save_message(payload) 没有任何变化。
  • 考虑直接向您的问题发布代码,而不是通过外部链接
  • 您不应该将message["message"] 传递给save_message 函数中的变更集吗?
  • @EvaldoBratti 如果我这样做会引发错误。 ** (Ecto.CastError) expected params to be a map, got: "testing123"

标签: elixir phoenix


【解决方案1】:

在 handle_in 函数的 spawn 中使用了 %{name: user.name, message: payload["message"]})。由于有效载荷的映射是%{user: user.name, message: payload["message"]}),这似乎不起作用。

def handle_in("message:new", payload, socket) do
  user = Repo.get(User, socket.assigns.user_id)
  spawn(fn -> save_message(%{name: user.name, message: payload["message"]}) end)
  broadcast! socket, "message:new", %{user: user.name, message: payload["message"]}
  {:noreply, socket}
end

但刷新后,它仍然将用户获取为“未定义”。设置以下 format_message 函数可解决该问题。

defp format_msg(msg) do
 %{
    user: msg.name,
    message: msg.message
  }
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-30
    • 2017-02-12
    • 1970-01-01
    • 2018-03-19
    • 1970-01-01
    • 1970-01-01
    • 2014-07-26
    • 1970-01-01
    相关资源
    最近更新 更多