Я думаю, что ваш пример здесь похож на решение для вашего другого примера , вам просто нужно закрыть несколько запросов с помощью вызова функции transaction/1
:
alias Ecto.Multi
alias Ecto.Repo
user = get_user_params_from_form() # <-- or where-ever you are getting data
email = get_email_params_from_form()
Multi.new()
|> Multi.insert(:user, User.changeset(%User{}, user))
|> Multi.insert(
:email,
# Capture the id from the previous operation
fn %{
user: %User{
id: user_id
}
} ->
Email.changeset(%Email{user_id: user_id}, email)
end
)
|> Repo.transaction()
Лично я не считаю, что с Multi
очень легко работать, поэтому иногда я предпочитаю этот другой синтаксис, где вы можете передать функцию в обратный вызов Repo.transaction / 2 . В общем, это выглядит примерно так:
Repo.transaction(fn ->
with {:ok, thing1} <- create_thing1(attrs1) do
create_thing2(attrs2)
else
{:error, e} -> Repo.rollback(e)
end
end)
def create_thing1(attrs \\ %{}) do
%ThingOne{}
|> ThingOne.changeset(attrs)
|> Repo.insert()
end
def create_thing2(attrs \\ %{}) do
%ThingTwo{}
|> ThingTwo.changeset(attrs)
|> Repo.insert()
end
Следует отметить, что этот шаблон можно использовать для переноса любой задачи в транзакции. Например, если "thing2" должен взаимодействовать со сторонним API, например.