如何更新 Phoenix 中模型的关系?

How to update relation of a model in Phoenix?

当我尝试在我的 MyDb 应用程序中编辑 book 时,我收到以下错误消息:

you are attempting to change relation :people of MyDb.Book, but there is missing data.

以下是相关片段:

/web/models/book.ex

defmodule MyDb.Book do
use MyDb.Web, :model
  schema "books" do
    field :title, :string
    field :note, :string
    many_to_many :people, MyDb.Person, join_through: MyDb.BookPerson
    timestamps()
  end

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

  defp parse_people_ids(params) do
    (params["people_ids"] || [])
    |> Enum.map(&get_people/1)
  end

  defp get_people(id) do
      MyDb.Repo.get_by(MyDb.Person, id: id)
  end
end

我可以保存与此变更集的关系。

/web/controllers/book_controller.ex

  def edit(conn, %{"id" => id}) do
    book = Repo.get!(Book, id)|> Repo.preload(:people) 
    people = Repo.all(Person) |> Enum.map(&{&1.surname, &1.id})
    changeset = Book.changeset(book)
    render(conn, "edit.html", book: book, changeset: changeset, conn: conn, people: people)
  end

  def update(conn, %{"id" => id, "book" => book_params}) do
    book = Repo.get!(Book, id)
    changeset = Book.changeset(book, book_params)

    case Repo.update(changeset) do
      {:ok, book} ->
        conn
        |> put_flash(:info, "Book updated successfully.")
        |> redirect(to: book_path(conn, :show, book))
      {:error, changeset} ->
        render(conn, "edit.html", book: book, changeset: changeset)
    end
  end

/web/templates/book/form.html.eex

  <div class="form-group">
    <%= label f, "Authors", class: "control-label" %>
    <%= multiple_select f, :people_ids, @people, class: "form-control" %>
    <%= error_tag f, :person_id %>
  </div>

错误消息下的评论说如果我想更新现有条目但我不知道如何更新,我应该在数据旁边包括条目主键 (ID)。

需要在 books 架构中使用选项 on_replace: :delete

 schema "books" do
    field :title, :string
    field :note, :string
    many_to_many :people, MyDb.Person, join_through: MyDb.BookPerson, on_replace: :delete
    timestamps()
  end