Richard Holland
Richard Holland

Reputation: 2673

Ecto.Changeset related model error on update

Ecto is giving me an error on updating a has_one association:

Model in question:

defmodule Something.Parent do
  has_one :thing, Something.thing

  @required_fields ~w(field1 field2 thing)
end

Controller update action

def update(conn, %{"id" => id, "parent" => parent_params}) do                            
   parent = Repo.get!(Parent, id) |> Repo.preload(:thing)

   changeset = Parent.changeset(parent, parent_params)                                                        

   case Repo.update(changeset) do
     {:ok, _parent} ->                                                                            
       conn                                                                                     
       |> put_flash(:info, "Parent updated successfully")                                         
       |> redirect(to: parent_path(conn, :index))                                                                             
     {:error, changeset} ->
       render(conn, "edit.html", parent: parent, changeset: changeset) 
   end                                                               
 end

Params

parent = %{"some_number" => "902", "thing" => %{"somethingfield" => "blah", "parent_id" => "8"}

Error

you are attempting to change relation :thing of
Whatever.Parent, but there is missing data.

By default, if the parent model contains N children, at least the same
N children must be given on update. In other words, it is not possible
to orphan embed nor associated records, attempting to do so results
in this error message.

It is possible to change this behaviour by setting :on_replace when
defining the relation. See `Ecto.Changeset`'s section on related models
for more info.

Based on the docs it looks like the changeset function on the parent model is seeing the 'Thing' being orphaned from the parent - but I can't see why?

The new/create actions work just fine.

Upvotes: 2

Views: 2215

Answers (2)

Cory Schmitt
Cory Schmitt

Reputation: 11

This was a bug in Ecto. Fixed on master with this commit.

https://github.com/elixir-lang/ecto/commit/6c1c04304ebecf5ccae4a49008deab814e034d2b

Upvotes: 1

Gazler
Gazler

Reputation: 84140

The problem here is that you have a thing associated to the parent you are changing.

As the error message specifies, you can change this with the on_replace option of has_one/3

:on_replace - The action taken on associations when the model is replaced when casting or manipulating parent changeset. May be :raise (default), :mark_as_invalid, :nilify, or :delete. See Ecto.Changeset‘s section on related models for more info.

Ecto.Changeset docs.

Upvotes: 2

Related Questions