How to make forms and transactions play well in phoenix + ecto?

本小妞迷上赌 提交于 2019-12-04 15:23:39

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)

if create_some_object doesn't return a struct matching {:ok, first_object} then the second_object is never created. Cool, right?

You can try with Ecto.Multi.Here's an example:

defmodule Service do
  alias Ecto.Multi
  import Ecto

  def insert_changeset(params) do
    Multi.new
    |> Multi.insert(:user, User.email_changeset(%User{}, params))
    |> Multi.insert(:invitation, Invitation.changeset(%Invitation{}, params))
  end
end

And your create function:

def create(params) do
  Service.insert_changeset(params)
  |> Repo.transaction
end

Or you can pattern matching to make your code nicer

  def create(params) do
    Repo.transaction(fn ->
      changeset = User.email_changeset(%User{}, params)
      changeset
      |> Repo.insert
      |> invitation_insert(params)
    end)
  end

  defp invitation_insert({:error, changeset}, _params), do: Repo.rollback(changeset)
  defp invitation_insert({:ok, _}, params) do
    Invitation.changeset(%Invitation{}, params)
    |> Repo.insert
    |> do_invitation_insert
  end

  defp do_invitation_insert({:ok, user}), do: user
  defp do_invitation_insert({:error, changeset}), do: Repo.rollback(changeset)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!