I overrode the Ecto NotLoaded
association because in my controller the json(conn, ad_campaign)
would fail if any relation of ad_campaign
was nil
, and I really didn’t want to manually craft every single response and would prefer to use the json/2
method.
So I did this:
defimpl Jason.Encoder, for: Ecto.Association.NotLoaded do
def encode(_, opts) do
Jason.Encode.map(%{}, opts)
end
end
This solved the problem well enough, but then when I tried to release the app, I get this error:
** (Mix) Duplicated modules:
'Elixir.Jason.Encoder.Ecto.Association.NotLoaded' specified in amplify and ecto
I understand this error - is there a way I can override nicely?
There is not. Duplicate protocol implementations are considered a problem to be fixed by elixir, not one to be worked around.
Imo the proper way to solve this is to be explicit about which data should be included in the json format and not include incorrect data – not loaded could be an existing association or no existing association.
Protocols are also a problematic way of doing encoding for APIs, because a single datatype might need to encode to multiple distinct json representations: Phoenix Views for JSON APIs | Benjamin Milde
4 Likes
There is a way
defmodule Overrider do
@on_load :override
def override do
defmodule :"Elixir.COMPLETE MODULE NAME HERE" do
...
end
:ok
end
end
You can safely inner defmodule
with defimpl
, but you have to disable protocol consolidation in project configuration.
This is a dark magic, but please, embrace it, make everybody get goosebumps from this