Error on update record with embeds_many field

I"m trying to update a record with an embeds_many field, but get the error listed in (3) below. In the schema for the parent object, I use on_replace: :delete, since without it I also get an error on update. The ecto docs suggest using this, but something must still not be right. I can create data in the embeds_many field. But once created, I cannot change it. (See Note (4))

(1) Schema of parent object

schema "documents" do
    field :content, :string
    field :rendered_content, :string
    field :title, :string
    field :author_id, :integer
    field :attributes, :map
    field :tags, {:array, :string}
    field :identifier, :string
    embeds_many :children, Child, on_replace: :delete

    timestamps()
  end

(2) Child schema

defmodule Child do
  use Ecto.Schema
  import Ecto.Changeset

  embedded_schema do
    field :level, :integer
    field :title, :string
    field :doc_id, :integer
    field :doc_identifier, :string
    field :comment, :string
  end

  def changeset(%Child{} = child, attrs) do
    child
    |> cast(attrs, [:level, :title, :doc_id, :doc_identifier, :comment])
  end

end

(3) Error message

[debug] QUERY OK db=8.2ms
UPDATE "documents" SET "children" = $1, "updated_at" = $2 WHERE "id" = $3 [[%{comment: "Basic Vocabulary", doc_id: 497, doc_identifier: "jxxcarlson.basic_vocabulary.2017-6-23@17:31:50.2a332f", id: "6510069c-b877-4983-a49f-cec0cf1687e9", level: 2, title: "Basic Vocabulary"}], {{2017, 7, 9}, {10, 8, 25, 350437}}, 495]
[info] Sent 500 in 48ms
[error] #PID<0.529.0> running Koko.Web.Endpoint terminated
Server: localhost:4000 (http)
Request: PUT /api/documents/495
** (exit) an exception was raised:
    ** (WithClauseError) no with clause matching: %Koko.DocManager.Document{__meta__: #Ecto.Schema.Metadata<:loaded, "documents">, attributes: %{"doc_type" => "master", "public" => true, "text_type" => "plain"}, author_id: 2, children: [%Child{comment: "Basic Vocabulary", doc_id: 497, doc_identifier: "jxxcarlson.basic_vocabulary.2017-6-23@17:31:50.2a332f", id: "6510069c-b877-4983-a49f-cec0cf1687e9", level: 2, title: "Basic Vocabulary"}], content: "== 496 // Introduction\n== 497 // Basic Vocabulary\n// test this\n\n\n", id: 495, identifier: "jxxcarlson.python_notes.2017-6-23@15:0:52.ec70e2", inserted_at: ~N[2017-06-23 15:00:52.328038], rendered_content: "== 496 // Introduction\n== 497 // Basic Vocabulary\n// test this\n\n\n", tags: [], title: "Python Notes", updated_at: ~N[2017-07-09 10:08:25.350437]}
        (koko_web) lib/koko_web/controllers/document_controller.ex:123: Koko.Web.DocumentController.update/2
        (koko_web) lib/koko_web/controllers/document_controller.ex:1: Koko.Web.DocumentController.action/2
        (koko_web) lib/koko_web/controllers/document_controller.ex:1: Koko.Web.DocumentController.phoenix_controller_pipeline/2
        (koko_web) lib/koko_web/endpoint.ex:1: Koko.Web.Endpoint.instrument/4
        (phoenix) lib/phoenix/router.ex:278: Phoenix.Router.__call__/1
        (koko_web) lib/koko_web/endpoint.ex:1: Koko.Web.Endpoint.plug_builder_call/2
        (koko_web) lib/plug/debugger.ex:123: Koko.Web.Endpoint."call (overridable 3)"/2
        (koko_web) lib/koko_web/endpoint.ex:1: Koko.Web.Endpoint.call/2
        (plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
        (cowboy) /Users/carlson/dev/apps/koko_umbrella/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4

(4) Note
If I do not have the , on_replace: :delete phrase, the error message is

[error] #PID<0.656.0> running Koko.Web.Endpoint terminated
Server: localhost:4000 (http)
Request: PUT /api/documents/495
** (exit) an exception was raised:
    ** (RuntimeError) you are attempting to change relation :children of
Koko.DocManager.Document, but there is missing data.

If you are attempting to update an existing entry, please make sure
you include the entry primary key (ID) alongside the data.

If you have a relationship with many children, at least the same N
children must be given on update. By default it is not possible to
orphan embed nor associated records, attempting to do so results in
this error message.

If you don't desire the current behavior or if you are using embeds
without a primary key, it is possible to change this behaviour by
setting `:on_replace` when defining the relation. See `Ecto.Changeset`'s
section on related data for more info.

*(5) Note
I added @primary_key false to the embedded schema. No change in error message.

‘3’ is a simple WithClauseError no with clause matching: - where you are failing to pattern match the result in your “with” clause…

for the rest I think you need to post more code, and what you expect to happen, and what is misbehaving.

1 Like

Thanks!

I think I see another place in the code where the problem lies … investigating now.

All fixed now. Thanks for the pointer … I was looking for the problem in the wrong place!

1 Like