gpt4 book ai didi

mysql - Phoenix-Framework : transform, 在创建子模型时关联和不检查 Ecto 父模型

转载 作者:可可西里 更新时间:2023-11-01 08:05:13 24 4
gpt4 key购买 nike

我正从 Rails 转向 Phoenix 框架。到目前为止,这是一个相当容易的过渡。不过,Phoenix 较新,我在查找一些特定信息时遇到了麻烦:

我正在使用我的 Phoenix 应用程序作为 API 服务层。
我希望我的 UI 表单(和传入的 curl 请求)使用 virtual field 来查找关联的父模型,并使用适当的属性填充子模型的 changeset。到目前为止,还不错:

在我的 child 模型中:

schema "child" do
field :parent_name, :string, virtual: true
belongs_to :parent, MyApp.Parent
end

...

before_insert :find_and_fill_parent

def find_and_fill_parent(changeset) do
parent = MyApp.Repo.get_by(
MyApp.Parent,
parent_name: changeset.changes.parent_name
)

changeset
|> Ecto.Changeset.put_change(:parent_id, parent.id)
end

这就是我卡住的地方。我不想让 child 在没有 parent 的情况下被创造出来。我如何以及在何处nil 检查父模型?尽管有条件语句,但我尝试过的所有操作都已无条件地阻止或允许创建。

看来我需要在检查之前预加载父模型,因为 Phoenix 旨在防止像我这样的人滥用延迟加载。不幸的是,我不知道一般正确的加载模式是什么,所以我不确定如何在这里应用它。 (如果相关的话,我正在使用 MySQL)

非常感谢有关查看位置和查看内容的提示和提示,以帮助我解决这个问题!谢谢! 😃

---编辑---
根据@Gazler 的建议,我已确保我的子模型迁移具有引用:

create table(:child) do
add :parent_id, references(:parent)
end

我还是有点迷路——我想通过父字段parent_name ("Jane Doe") 找到parent , 确保父模型存在,并使用 parent_id (1) 关联子模型。我不确定如何使用虚拟字段触发这些操作。

因此,我不确定如何构建查找父项、建立关联和检查外键验证的结构,因为原始参数中永远不会存在外键。想法?

非常感谢。

---已解决---
使用@Gazler 的更新答案,我可以在没有虚拟属性或 before_insert 的情况下成功地在子 Controller 中检查我的父模型。

def create(conn, %{"post" => post_params}) do 
user = Repo.get_by(User, %{name: post_params["name"]})
if is_nil(user) do
changeset = Post.changeset(%Post{}, post_params)
else
changeset = build(user, :posts) |> Post.changeset(post_params)
end
etc
end

这会完全按照我的需要验证传入的参数!谢谢@Gazler!

最佳答案

before_insert 可能不是执行此操作的正确位置。

您正在使用 belongs_to 关联,但是如果您在另一侧包含 has_many 关联,那么您可以使用 build/3填写父id:

build(user, :posts)

这只是一个函数,用于填充结构的 post_id 字段 - 它不会验证 user 是否实际存在。

如果您想在创建帖子之前确保用户存在,那么您可以使用 foreign_key_constraint/3在你的变更集上:

cast(comment, params, ~w(user_id), ~w())
|> foreign_key_constraint(:user_id)

这将在数据库级别确保父项的记录存在。如果您的迁移看起来像这样,您需要在数据库中创建索引:

create table(:posts) do
add :user_id, references(:user)
end

编辑

不需要虚拟属性。您的 Controller 操作应类似于:

def create(conn, %{"name" => name, "post" => post_params}) do
user = Repo.get_by(User, %{name: name})
changeset = build(user, :posts) |> Post.changeset(post_params)
case Repo.insert(changeset) do
{:ok, post} -> ...
{:error, changeset} -> #if constraint is violated then the error will be in the changeset
end
end

关于mysql - Phoenix-Framework : transform, 在创建子模型时关联和不检查 Ecto 父模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32994884/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com