我正在尝试向Phoenix应用添加duplicate
函数,该应用会获取Page
个对象和owner_id
并创建一个具有相同字段的新Page
,但是由其他人拥有。现在它看起来像这样:
def duplicate(%Page{} = page, new_owner_id) when is_integer(new_owner_id) do
page
|> Page.changeset(%{owner_id: new_owner_id})
|> Repo.insert()
end
测试此错误会抛出此错误:
(RuntimeError) attempting to cast or change association `owner` from `Page` that was not loaded. Please preload your associations before manipulating them through changesets
我不想操纵用户关联中的字段。我只是想改变哪个用户关联。我相信这应该是可能的,而不会抛出关联(有一个blog post关于做到这一点)但我无法弄清楚如何让这个错误消失。我错过了什么?
代码的其他相关部分(简化):
变更集功能:
def changeset(%Page{} = page, attrs) do
page
|> cast(attrs, [:owner_id])
|> foreign_key_constraint(:owner_id)
end
架构:
schema "pages" do
belongs_to :owner, User
timestamps()
end
迁移:
def change do
create table(:pages) do
add :owner_id, references(:users, on_delete: :nothing)
timestamps()
end
create index(:pages, [:owner_id])
end
答案 0 :(得分:0)
关联宏给出options for how to handle replacing associations。默认情况下是引发错误,但如果您希望将其更改为正常的外键定义,则可以将:on_replace
设置为:update
。所以它看起来像:
belongs_to :owner, User, [on_replace: :update]
我有一个跟进问题:错误还意味着Page结构已经是来自DB的加载记录。我不认为您想尝试重新插入相同的记录,而是通过params地图创建一个新的页面,从原始页面结构中复制数据。
即使它不是现有记录,而是某种中介%Page{}
(例如没有主键),您可能会考虑将复制登录本身放在复制函数中:
def duplicate(%Page{example_data: example_data} = original_page, new_owner_id) when is_integer(new_owner_id) do
%Page{}
|> Page.changeset(%{example_data: example_data, owner_id: new_owner_id})
|> Repo.insert()
end