1

I have a simple model (short version) :

defmodule MyApp.User do
  use Ecto.Model

  @derive {Poison.Encoder, only: [:id, :name, :email]}
  schema "users" do
    field :name, :string
    field :email, :string
    belongs_to :company, MyApp.Company

I expect the @derive to exclude :company associations while trying to encode the model, but it doesn't seem to. This happens while using Guardian serializer :

defmodule MyApp.GuardianSerializer do
  @behaviour Guardian.Serializer

  alias MyApp.Repo
  alias MyApp.User

  def for_token(user = %User{}), do: { :ok, "User:#{user.id}" }
  def for_token(_), do: { :error, "Unknown resource type" }

  def from_token("User:" <> id), do: { :ok, Repo.get(User, id) }
  def from_token(_), do: { :error, "Unknown resource type" }
end

I'm not actually sure to understand what happens with

def for_token(user = %User{}), do: { :ok, "User:#{user.id}" }

From what i understand user = %User{} is trying to test if the object given as a parameter is a valid User changeset right ?

But i get this error instead :

cannot encode association :company from MyApp.User to JSON because the association was not loaded. Please make sure you have preloaded the association or remove it from the data to be encoded

I do not want to preload it, because it will require more dependencies to encode which doesn't work either, i would prefer to ignore it.

Why the only param in @derive doesn't work and how could I resolve this issue ?

Sylver
  • 2,285
  • 3
  • 29
  • 40
  • Do you get the same error if you do `Poison.encode!(Repo.get(User, 1))` (replacing 1 with a valid user id)? – Dogbert Jul 12 '16 at 01:35
  • I have updated the question and added some context. Yes the same problem occurs if i try to encode it directly with `Poison.encode!/1` – Sylver Jul 12 '16 at 08:50
  • 1
    I cannot reproduce this with a similar setup: `Comment` belongs_to `Post`; `Poison.encode!(Repo.get(Comment, 1))` with `@derive {Poison.Encoder, only: [:id, :content]}` on `Comment`. Can you try to reproduce the error in a new minimal app? – Dogbert Jul 12 '16 at 09:06
  • Are you preloading the association ? If I preload it, the error continues with associations of `Company` which are not preloaded... but i don't want to preload or encode any of these. – Sylver Jul 12 '16 at 09:10
  • Yes, even this works fine: `Poison.encode! MyApp.Repo.get(MyApp.Comment, 2) |> MyApp.Repo.preload([:post])` with the same `@derive` as I posted in the previous comment. – Dogbert Jul 12 '16 at 09:36
  • No, it doesn't work, it requires to load the associations even with `@derive` set. I don't know what's wrong and why you don't have any issue – Sylver Jul 12 '16 at 09:50
  • I'm testing on `poison` 2.2.0, `ecto` 2.0.2 and `phoenix` 1.2.0. – Dogbert Jul 12 '16 at 10:01
  • @Sylver any updates? I've checked with model which uses guardian and it works for me too. May be something which we aren't see in your example? – Евгений Масленков Jul 13 '16 at 07:23

1 Answers1

0

I finally found the problem.

I had a fix in my project related to an older version of Ecto, you can find a discussion about that here, and the suggestion for the fix i used here

So, basically i was already redefining the Poison.Encoder elsewhere, for everything (I know, this is pretty bad to have done that, and as usual, it was something meant to be temporary...)

defimpl Poison.Encoder, for: Any do
  def encode(%{__struct__: _} = struct, options) do
    map = struct
          |> Map.from_struct
          |> sanitize_map
    Poison.Encoder.Map.encode(map, options)
  end

  defp sanitize_map(map) do
    Map.drop(map, [:__meta__, :__struct__])
  end
end

By removing it, with the last version of ecto/poison/phoenix/you-name-it, it works as expected.

Thanks a lot for your help @dogbert

Sylver
  • 2,285
  • 3
  • 29
  • 40