在我的凤凰应用中,我在尝试更新no function clause matching in Ecto.Changeset.change/2
关系的模型时遇到embeds_many
错误。我已经阅读了文档,并看到了其他相关内容,但我无法弄清楚我做错了什么。
首先,这是错误:
** (FunctionClauseError) no function clause matching in Ecto.Changeset.change/2
(ecto) lib/ecto/changeset.ex:307: Ecto.Changeset.change(%{"content" => "<p>Nice to see you</p>", "duration" => 15, "id" => "93387d2d-a6ed-4902-911f-4dc1525aca2b"}, %{})
(ecto) lib/ecto/changeset/relation.ex:196: Ecto.Changeset.Relation.on_replace/2
(ecto) lib/ecto/changeset/relation.ex:299: Ecto.Changeset.Relation.reduce_delete_changesets/5
(ecto) lib/ecto/changeset.ex:691: Ecto.Changeset.cast_relation/4
(myapp) web/models/agenda.ex:20: MyApp.Agenda.changeset/2
父母&#39;模型为Agenda
,嵌入模型为AgendaPage
。模型定义如下:
agenda.ex
defmodule MyApp.Agenda do
use MyApp.Web, :model
@primary_key {:id, :string, []}
@derive {Phoenix.Param, key: :id}
schema "agenda" do
field :name, :string
embeds_many :pages, MyApp.AgendaPage, on_replace: :delete
end
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:name])
|> cast_embed(:pages)
|> validate_required([:name])
end
end
agenda_page.ex
defmodule MyApp.AgendaPage do
use MyApp.Web, :model
embedded_schema do
field :content, :string
field :duration, :integer
end
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:content, :duration])
end
end
来自update
的{{1}}行动
agenda_controller.ex
在def update(conn, %{"id" => id, "agenda" => agenda_params}) do
agenda = Repo.get!(Agenda, id)
changeset = Agenda.changeset(agenda, agenda_params)
case Repo.update(changeset) do
{:ok, agenda} ->
json conn, %{status: "ok", agenda: agenda}
{:error, changeset} ->
errors = parse_errors(changeset)
IO.inspect errors
json(conn |> put_status(400), %{status: "error", message: "Failed to update Agenda", errors: errors})
end
end
终端中,我可以使用iex
访问现有议程,这会回复以下记录:
MyApp.Repo.get(MyApp.Agenda, "default_agenda")
将在控制器操作中传递给变更集的%MyApp.Agenda{__meta__: #Ecto.Schema.Metadata<:built, "agenda">,
id: "default_agenda", name: "Default Agenda",
pages: [%{"content" => "<p>This is the default agenda</p>", "duration" => 10,
"id" => "0849862a-0794-4466-88a3-6052da360ca0"},
%{"content" => "<p>Nice to see you</p>", "duration" => 15,
"id" => "93387d2d-a6ed-4902-911f-4dc1525aca2b"}]}
示例如下所示:
agenda_params
但是尝试通过我的更新操作运行此数据会产生错误。任何人都可以提供一些指导吗?
答案 0 :(得分:0)
首先,以下看起来不正确:
%MyApp.Agenda{__meta__: #Ecto.Schema.Metadata<:built, "agenda">,
id: "default_agenda", name: "Default Agenda",
pages: [%{"content" => "<p>This is the default agenda</p>", "duration" => 10,
"id" => "0849862a-0794-4466-88a3-6052da360ca0"},
%{"content" => "<p>Nice to see you</p>", "duration" => 15,
"id" => "93387d2d-a6ed-4902-911f-4dc1525aca2b"}]}
pages
列表应该是AgendaPage结构列表,而不是地图,如下面的示例所示。我不确定你是怎么做到的。
然而,主要问题似乎是在你的参数中提供id
字段。尝试根据上面的示例参数更新现有记录时,我遇到了同样的问题。但是,如果你从更新中的params中删除id字段,它就可以工作。
这是一个有效的例子:
iex(4)> {:ok, ag} = Repo.insert Agenda.changeset(%Agenda{id: "default_agenda"}, %{name: "Default Agenda"})
[debug] QUERY OK db=9.7ms
INSERT INTO "agendas" ("id","name","inserted_at","updated_at") VALUES ($1,$2,$3,$4) ["default_agenda", "Default Agenda", {{2017, 7, 21}, {23, 43, 46, 739178}}, {{2017, 7, 21}, {23, 43, 46, 747000}}]
{:ok,
%Playground.Demo.Agenda{__meta__: #Ecto.Schema.Metadata<:loaded, "agendas">,
id: "default_agenda", inserted_at: ~N[2017-07-21 23:43:46.739178],
name: "Default Agenda", pages: [],
updated_at: ~N[2017-07-21 23:43:46.747000]}}
iex(5)> Repo.update Agenda.changeset(ag, %{
...(5)> "name" => "Default Agenda",
...(5)> "pages" => [
...(5)> %{
...(5)> "content" => "<p>foo</p>",
...(5)> "duration" => 10,
...(5)> "id" => "0849862a-0794-4466-88a3-6052da360ca0"
...(5)> },
...(5)> %{
...(5)> "content" => "<p>bar</p>",
...(5)> "duration" => 15,
...(5)> "id" => "93387d2d-a6ed-4902-911f-4dc1525aca2b"
...(5)> }
...(5)> ]
...(5)> }
...(5)> )
[debug] QUERY OK db=15.7ms
UPDATE "agendas" SET "pages" = $1, "updated_at" = $2 WHERE "id" = $3 [[%{content: "<p>foo</p>", duration: 10, id: "e7b5b7d9-9308-43f0-8bc7-c5956640772b"}, %{content: "<p>bar</p>", duration: 15, id: "1c668d06-5c60-4a4d-a052-43520597162d"}], {{2017, 7, 21}, {23, 44, 23, 752892}}, "default_agenda"]
{:ok,
%Playground.Demo.Agenda{__meta__: #Ecto.Schema.Metadata<:loaded, "agendas">,
id: "default_agenda", inserted_at: ~N[2017-07-21 23:43:46.739178],
name: "Default Agenda",
pages: [%Playground.Demo.AgendaPage{content: "<p>foo</p>", duration: 10,
id: "e7b5b7d9-9308-43f0-8bc7-c5956640772b"},
%Playground.Demo.AgendaPage{content: "<p>bar</p>", duration: 15,
id: "1c668d06-5c60-4a4d-a052-43520597162d"}],
updated_at: ~N[2017-07-21 23:44:23.752892]}}
iex(6)> Repo.get Agenda, "default_agenda"
[debug] QUERY OK source="agendas" db=7.2ms
SELECT a0."id", a0."name", a0."pages", a0."inserted_at", a0."updated_at" FROM "agendas" AS a0 WHERE (a0."id" = $1) ["default_agenda"]
%Playground.Demo.Agenda{__meta__: #Ecto.Schema.Metadata<:loaded, "agendas">,
id: "default_agenda", inserted_at: ~N[2017-07-21 23:43:46.739178],
name: "Default Agenda",
pages: [%Playground.Demo.AgendaPage{content: "<p>foo</p>", duration: 10,
id: "e7b5b7d9-9308-43f0-8bc7-c5956640772b"},
%Playground.Demo.AgendaPage{content: "<p>bar</p>", duration: 15,
id: "1c668d06-5c60-4a4d-a052-43520597162d"}],
updated_at: ~N[2017-07-21 23:44:23.752892]}
iex(7)>