I have the Ecto model below. When I render, I want the JSON to substitute the property name "layers" for "tilemap_layers".
There are many types of 'layers' in my application, so when I made my database schema, I needed to make a uniquely named schema. However, this JSON will be consumed by a third-party client where it must be named "layers".
What is the recommended way to do this?
The model is here:
defmodule MyProject.Tilemap do
use MyProject.Web, :model
@derive {Poison.Encoder, only: [
:name,
:tile_width,
:tile_height,
:width,
:height,
:orientation,
:tilemap_layers,
:tilesets
]}
schema "tilemaps" do
field :name, :string
field :tile_width, :integer
field :tile_height, :integer
field :width, :integer
field :height, :integer
field :orientation, :string
has_many :tilemap_layers, MyProject.TilemapLayer
has_many :tilesets, MyProject.Tileset
timestamps
end
@required_fields ~w(tile_width tile_height width height)
@optional_fields ~w()
@doc """
Creates a changeset based on the `model` and `params`.
If no params are provided, an invalid changeset is returned
with no validation performed.
"""
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
end
end
Poison does not provide a way to alias when using @deriving
You can either:
specify the implementation yourself with defimpl
(taken from the docs):
defimpl Poison.Encoder, for: Person do
def encode(%{name: name, age: age}, _options) do
Poison.Encoder.BitString.encode("#{name} (#{age})")
end
end
Rename the field in the schema:
has_many :layers, MyProject.TilemapLayer
or use a Phoenix View:
defmodule MyProject.TilemapView do
use MyProject.Web, :view
def render("index.json", %{tilemaps: timemaps}) do
render_many(tilemaps, __MODULE__, "tilemap.json")
end
def render("tilemap.json", %{tilemap: tilemap}) do
%{
name: tilemap.name,
...
layers: render_many(layers, MyProject.TilemapLayerView, "tilemap_layer.json")
}
end
end
Then create a TilemapLayerView:
defmodule MyProject.TilemapLayerView do
use MyProject.Web, :view
def render("tilemap_layer.json", %{tilemap_layer: tilemap_layer}) do
%{
name: timemap_layer.name
}
end
end