Poison.Encoder 如何预加载关联?

Jos*_*itt 2 elixir ecto phoenix-framework

我有下面的 Ecto 模型。当我尝试渲染时出现错误。如何修改 @derive 以使其预加载?还是我必须写出实现?处理这个问题的推荐方法是什么?

** (RuntimeError) cannot encode association :tilemap_layers from MyProject.Tilemap 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
Run Code Online (Sandbox Code Playgroud)

模型在这里:

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
Run Code Online (Sandbox Code Playgroud)

Gaz*_*ler 5

简短的回答是你不应该。预加载数据不是视图层的责任。

您应该在获取资源(通常是控制器或从控制器调用的函数)时执行预加载。

例如使用Ecto.Repo.preload/3

def index(_conn, _params)
  timemaps = Tilemap |> Repo.all() |> Repo.preload(:timemap_layers)
  render("index.json", tilemaps: tilemaps)
end
Run Code Online (Sandbox Code Playgroud)

您还可以使用Ecto.Query.preload/3在查询中执行预加载:

query = from t in Tilemap,
  preload: [:tilemap_layers]
Repo.all(query)
Run Code Online (Sandbox Code Playgroud)