nonamorando
nonamorando

Reputation: 1605

Phoenix Channel `push` ** (Protocol.UndefinedError) protocol Jason.Encoder

Whenever a user joins a channel, I want to send them a record of all the previous messages that were sent.

My implementation for handle_info below triggers this error protocol Jason.Encoder not implemented for Hello.Messaging.Message.

My guess is that messages is a list of structs, when it needs to be converted to a list of maps?

  use Phoenix.Channel
  alias Hello.Messaging

  def join("room:" <> room_id, params, socket) do
    send(self(), {:after_join, params})
    {:ok, assign(socket, :room_id, room_id)}
  end

  # push triggers the error message here
  def handle_info({:after_join, _params}, socket) do
    messages = Messaging.list_messages()
    push(socket, "messages", %{messages: messages})
    {:noreply, socket}
  end

  def handle_in("new_msg", %{"body" => body}, socket) do
    case Messaging.create_message(%{body: body, room_id: socket.assigns.room_id}) do
      {:ok, msg} ->
        broadcast!(socket, "new_msg", %{body: msg.body})
        {:noreply, socket}

      {:error, reason} ->
        {:error, reason}
    end
  end

 

Upvotes: 1

Views: 199

Answers (2)

nonamorando
nonamorando

Reputation: 1605

I'm writing my own answer here.

The problem is that messages from Message.list_messages() is a list of structs, when push takes either a map or tagged {:binary, data} tuple.

Converting messages into a map was the solution:

map_messages = Enum.map(struct_messages, fn s_msg -> Map.take(s_msg, [:id, :body]) end)

Upvotes: 0

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

Jason.Encoder is not implemented for structs, and your Hello.Messaging.Message is a struct.

If you own the struct, enable encoding for it as described in the documentation

@derive {Jason.Encoder, only: [....]}
defstruct # ...

If you cannot modify the struct, convert it to map with Map.from_struct/1.

Upvotes: 1

Related Questions