问题描述
我正在与Phoenix + Ecto玩,偶然发现了一些我觉得不习惯的东西.
I'm playing with Phoenix + Ecto and I stumbled upon something that does not feel idiomatic to me.
我有一个表示Invitation
的表格.创建邀请时,我们还需要创建一个User
,显然我希望两者都在事务中发生,以便保持数据一致性.在我的表单中,我要求输入name
和email
.
I have a form that represents an Invitation
. When creating an Invitation we also need to create a User
and obviously I want both to happen in a transaction so I keep data consistency. In my form I ask for name
and email
.
因为我希望视图中的Invitation
变更集能够正确表示错误,所以我最终获得了这段代码...但是看起来并不好.
Since I want the Invitation
changeset in my view to represent the errors correctly I ended up with this code... but does not look great.
您知道在Phoenix + Ecto中执行此操作的更好方法吗?
Do you know a better way to do this in Phoenix + Ecto?
def create(params) do
Repo.transaction(fn ->
case Repo.insert(User.email_changeset(%User{}, params)) do
{:ok, user} ->
changeset = Invitation.changeset(%Invitation{}, params)
case Repo.insert(Ecto.Changeset.change(changeset, user_id: user.id)) do
{:ok, user} ->
user
{:error, changeset} ->
Repo.rollback(changeset)
end
{:error, _changeset} ->
Repo.rollback(%{Ecto.Changeset.add_error(changeset, :email, "Wrong email") | action: :insert})
end
end)
end
推荐答案
您正在寻找with
运算符.这种语法的妙处在于,如果您在任何时候都没有得到期望的结果,它将停止命令链并触发您的else
块:
You are looking for the with
operator. The beauty of this syntax is that if, at any point, you don't get what you're expecting, it stops the chain of commands and fires your else
block:
Repo.transaction(fn ->
with {:ok, first_object} <- create_some_object,
{:ok, second_object} <- create_another(first_object.something) do
second_object
else
{:error, error_key} ->
Repo.rollback(error_key)
end
end)
如果create_some_object
没有返回与{:ok,first_object}匹配的结构,则永远不会创建second_object.太酷了吧?
if create_some_object
doesn't return a struct matching {:ok, first_object} then the second_object is never created. Cool, right?
这篇关于如何使表格和交易在phoenix + ecto中很好地发挥作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!