2017-07-21 4 views
0

embeds_manyリレーションシップを持つモデルを更新しようとすると、Phoenixアプリケーションでno function clause matching in Ecto.Changeset.change/2エラーが発生します。私はドキュメントを読んでこれについての他の投稿を見ましたが、私が間違っていることを理解することはできません。embeds_manyレコードの更新時にPhoenix/Ecto - チェンジセットエラーが発生しました

まず第一に、ここでエラーがあります:

** (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 

'親' モデルは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 

そしてiexの端末で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 

からupdateアクションを、私はEにアクセスすることができます以下のレコードをバック与えMyApp.Repo.get(MyApp.Agenda, "default_agenda")とxistingの議題、:

%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の例は次のようになります。

%{ 
    "id" => "default_agenda", 
    "name" => "Default Agenda", 
    "pages" => [ 
    %{ 
     "content" => "<p>foo</p>", 
     "duration" => 10, 
     "id" => "0849862a-0794-4466-88a3-6052da360ca0" 
    }, 
    %{ 
     "content" => "<p>bar</p>", 
     "duration" => 15, 
     "id" => "93387d2d-a6ed-4902-911f-4dc1525aca2b" 
    } 
    ] 
} 

しかし、実行しようとしていますこのデータは更新処理によってエラーになります。誰かが何かガイダンスを提供できますか?

答えて

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)> 
+0

はい、あなたは正しい - スキーマに問題があるように思われます。私は少しをバックトラックする必要があります、あなたの投稿を維持します。私は「id」の問題について勘違いをしましたが、わかりませんでした。スティーブ、あなたの男! – skwidbreth

+0

スティーブ、あなたは正しい方向に私を指摘しましたが、私はそれを解決する方法を正確に把握しなければなりません。要するに、挿入されたレコードを取得すると、埋め込みモデルへの参照を保持していないということです。私は 'pages:[%{" MyApp .AgendaPage {"content" ...}。 「id」の問題も問題でしたが、これが大きな問題です。私は実際にはPostgresを使用していません - 実験的なDynamoDBアダプタを使用しています...その構造を保存する方法を理解する必要があります。 – skwidbreth

+0

私は、チェンジセットに渡された最初の引数にモデル参照を手動で追加することによって、正常な更新を行うことができました。スティーブ、あなたの視点でおかげさまで100万ドル! – skwidbreth

関連する問題