我正在尝试使用Ecto 2 rc。
我的模特是:
schema "containers" do
field :name, :string
many_to_many :items, Test.Item, join_through: Test.ContainerItem, on_delete: :delete_all
timestamps
end
schema "items" do
field :content, :string
many_to_many :containers, Test.Container, join_through: Test.ContainerItem, on_delete: :delete_all
timestamps
end
schema "containers_items" do
belongs_to :container, Test.Container
belongs_to :item, Test.Item
timestamps
end
我的控制器代码是:
def add_item(conn, %{"item" => item_params, "container_id" => container_id}) do
item = Item.changeset(%Item{}, item_params)
IO.inspect(item) #TODO remove
container = Container |> Repo.get(container_id) |> Repo.preload([:items])
IO.inspect(container) #TODO remove
changeset = container
|> Ecto.Changeset.change
|> Ecto.Changeset.put_assoc(:items, [item])
IO.inspect(changeset) #TODO remove
if changeset.valid? do
Repo.update(changeset)
conn
|> put_flash(:info, "Item added.")
|> redirect(to: container_path(conn, :show, container))
else
render(conn, "show.html", container: container, changeset: changeset)
end
end
现在,如果我将一个项目添加到容器中,这可以正常工作。但是,如果容器上存在某个项目,那么尝试添加另一个项目会给我:
(RuntimeError)你试图改变关系:的项目 Test.Container,但缺少数据。
我情不自禁地觉得我的方式错了,一些建议值得赞赏。
答案 0 :(得分:3)
好的,所以我只想出来了。
我的问题是没有将项目转换为Changesets
,以便ecto
可以跟踪需要进行的更改。
我需要进行的唯一编辑是控制器。
它应该是这样的:
def add_item(conn, %{"item" => item_params, "container_id" => container_id}) do
item = Item.changeset(%Item{}, item_params)
IO.inspect(item) #TODO remove
container = Container |> Repo.get(container_id) |> Repo.preload([:items])
IO.inspect(container) #TODO remove
item_changesets = Enum.map([item | container.items], &Ecto.Changeset.change/1)
changeset = container
|> Ecto.Changeset.change
|> Ecto.Changeset.put_assoc(:items, item_changesets)
IO.inspect(changeset) #TODO remove
if changeset.valid? do
Repo.update(changeset)
conn
|> put_flash(:info, "Item added.")
|> redirect(to: container_path(conn, :show, container))
else
render(conn, "show.html", container: container, changeset: changeset)
end
end