As far as I know, the recommended (and easiest) way to JSON-encode your Ecto Schema in Phoenix is using the Poison.Encoder like so:
defmodule MyApp.Web.User do
use MyApp.Web, :model
@derive {Poison.Encoder, only: [:first_name, :last_name, :email]}
schema "users" do
field :first_name, :string
field :last_name, :string
field :email, :string
# ...
timestamps()
end
end
That works great as it allows me to simply return the User
schema in a show.json
Phoenix.View, for example, and then Poison would pick it up and serialize it.
However, I’m not sure what’s the best way to go if you want to do something extra, before returning the schema from the View.
Let’s say the user has a last_login
field that I’d like to convert from UTC to a specific timezone. The actual timezone string identifier is not part of the User schema, so it needs to be fetched separately. Also I would like to add a field that’s not part of the original User schema. Right now, I’m constructing a new Map and returning it from the Phoenix.View, like so:
defmodule MyApp.Web.UserView do
use MyApp.Web, :view
def render("show.json", %{....}) do
# ...
tz = organization.timezone
%{
first_name: user.first_name,
last_name: user.last_name,
org_name: organization.name,
last_login: Timex.Timezone.convert(user.last_login, tz)
}
end
end
That seems to work, but I’m not very keen on this approach as it is a lot of duplicated code; also if I want to return a list of 1000 users, this will construct 1000 maps just for encoding, which is not great.
Is there a better way to do this?
P.S. Forum moderators: I’m not sure if this topic belongs to the Phoenix, Ecto or a different category, so feel free to move it if it makes sense!