Poison.Encoder如何在渲染的JSON中重命名属性?

时间:2015-11-17 12:09:04

标签: json elixir phoenix-framework ecto

我有下面的Ecto模型。当我渲染时,我希望JSON将属性名称“layers”替换为“tilemap_layers”。

我的应用程序中有很多类型的“层”,因此当我创建数据库架构时,我需要创建一个唯一命名的架构。但是,此JSON将由第三方客户端使用,其中必须将其命名为“layers”。

建议的方法是什么?

模型在这里:

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

1 个答案:

答案 0 :(得分:3)

使用@deriving

时,Poison不提供别名方法

你可以:

使用defimpl(摘自the docs)自行指定实施:

defimpl Poison.Encoder, for: Person do
  def encode(%{name: name, age: age}, _options) do
    Poison.Encoder.BitString.encode("#{name} (#{age})")
  end
end

重命名架构中的字段:

has_many :layers, MyProject.TilemapLayer

或使用凤凰视图:

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

然后创建一个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