Cannot encode association to JSON because the association was not loaded or preloaded

The error message listed in the topic is I know posted on the web several times and I apologize that I haven’t been able to resolve in reasonable amount of time on my own - so here goes:

I am using channels to insert a new comment for a selected topic by the current user. This is so that the comment auto-updates the browser pages of other users.

The web app appears to run fine but I notices that after I added an association to the user table the auto refresh was no longer working when a new comment was added. Further investigation turned up the error message in the terminal where the Phoenix Server is running.

So I am following along a tutorial that states one way add the email field to each added comment inserted is to associate the comment changeset with the user table so I can pull the email from the user table info.

This does appear to work but as I said the auto-update is lost and there is an error message on the server.

This is the code that allowed adding the user info to the comment changeset and caused the prblem:

In the comment model file this line was changed by adding :user (a foreign key) to the derive list

@derive {Poison.Encoder, only: [:content, :user]}

In the comment_channel handler this code was added to “associate” the user info to the comment changeset

def handle_in(name, %{“content” => content}, socket) do
topic = socket.assigns.topic
user_id = socket.assigns.user_id

changeset = topic
  |> build_assoc(:comments, user_id: user_id)
  |> Comment.changeset(%{content: content})

case Repo.insert(changeset) do
  {:ok, comment} ->
    **broadcast!**(socket, "comments:#{socket.assigns.topic.id}:new",
      %{comment: comment}
    )
    {:reply, :ok, socket}
  {:error, _reason} ->
    {:reply, {:error, %{errors: changeset}}, socket}
end

end

You will probably need more to go on and I can provide github link or perhaps gist if needed.

Removing the extra :user from the @derive makes the error go away and the auto-update then works again but unfortunately then I have no way to extract the user email field to appear next to each comment.

My guess is that build_assoc does not play well with foreign keys or perhaps @derive is not the best way “expose” keys for relating tables.

1 Like

You have to preload the user. I can’t remember which preload as there are two: one in the Repo and one in Ecto.Query. But I’ve had that error before and resolved it by preloading.

Thanks I have been trying that path but so far I have not got the correct syntax or perhaps I am not preloading in the right section of the code. I know the user iID but since the comment is not yet inserted in the database is it enough to just preload the User record data so it is encoded prior to the build_assoc? IOW?

user_id = socket.assigns.user_id

changeset = topic
  |> Repo.get(user_id)
  |> Repo.preload(comments: [:user])
  |> build_assoc(:comments, user_id: user_id) 
  |> Comment.changeset(%{content: content})

Not sure if can just insert a |> Repo.get(…) into a pipeline designed to from a changeset?

I think this might be what you’re looking for:

case Repo.insert(changeset) do
  {:ok, comment} ->
    broadcast!(socket, "comments:#{socket.assigns.topic.id}:new",
      %{comment: Repo.preload(comment, :user)}
    )
    {:reply, :ok, socket}
  {:error, _reason} ->
    {:reply, {:error, %{errors: changeset}}, socket}
end
9 Likes

Wow!!! That worked perfectly. I didn’t think I was even describing the problem sufficiently for someone to be able to troubleshoot and resolve.

So I think the issue is that Ecto Elixir/Erlang structures need to be converted to javascript structures prior to passing them along to javascript code. And since the comment hadn’t been created until the Repo.insert(changeset) was finished there was no comment record available to be converted to JSON format. So the preload statement that you wrapped around the broadcast payload did the actual JSON conversion just prior to the payload being pushed back to the clients.

I will be moving on to latest version of Phoenix next and hope one day to be able to assist others as you have me.

While learning a visual debugger would be great and I think that there is one available for VSCode and maybe other IDE / Editors so I will be checking that out.

Thanks!!!

Thx voughtdq, your suggestion worked for me as well.

1 Like

Thx voughtdq that worked :slight_smile: