凤凰:使用has_many发布模型保持抛出预加载错误

时间:2017-06-21 07:36:42

标签: elixir phoenix-framework ecto

我将在此处显示一些相关代码,但如果您需要完整代码,可以在Github上找到它:https://github.com/maple-leaf/phoenix_todo

user_model:

defmodule PhoenixTodo.User do
  use PhoenixTodo.Web, :model

  @derive {Poison.Encoder, only: [:name, :email, :bio, :todos]}

  schema "users" do
    field :name, :string
    field :age, :integer
    field :email, :string
    field :bio, :string

    has_many :todos, PhoenixTodo.Todo

    timestamps()
  end

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:name])
    |> validate_required([])
  end
end

todo_model:

defmodule PhoenixTodo.Todo do
  use PhoenixTodo.Web, :model

  @derive {Poison.Encoder, only: [:title, :content]}

  schema "todos" do
    field :title, :string
    field :content, :string

    belongs_to :user, PhoenixTodo.User

    timestamps()
  end

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [])
    |> validate_required([])
  end
end

user_controller:

defmodule PhoenixTodo.UserController do
    use PhoenixTodo.Web, :controller

    alias PhoenixTodo.User

    def index(conn, _params) do
        json(conn, User |> Repo.all() |> Repo.preload(:todos))
    end

    def show(conn, %{"id" => id}) do
        json(conn, User|> Repo.get(id) |> Repo.preload(:todos))
    end

    def create(conn, data) do
      user = User.changeset(%User{}, data)
      #user = User.changeset(%User{}, %{name: "xxx", todos: [%PhoenixTodo.Todo{}]})
      json conn, user
    end
end

我可以从:index:show获取所有用户或查询特定用户,但:create将始终引发有关association的错误。

请求:curl -H "Content-Type: application/json" -X POST -d '{"name": "abc"}' http://localhost:4000/api/users

出现错误:cannot encode association :todos from PhoenixTodo.User 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

:todos时如何预加载:create?创建用户时todos不是必填字段,我们可以忽略该关联吗?

1 个答案:

答案 0 :(得分:0)

最后,我让它发挥作用。

事实证明json conn user很重要。似乎json会调用Poison来编码Ecto.Changeset而不是Ecto.Model ,它会按changeset返回。所以我们应该将Ecto.Model传递给json。

以下是我的表现方式。

user = User.changeset(%User{}, data)
IO.inspect user  # Ecto.Changeset
{:ok, u1} = Repo.insert(user)
IO.inspect u1   # Model!!
json conn, u1 |> Repo.preload(:todos)  # now we can successfully preload :todos