I’ve read in several places that try/rescue are to be generally avoided. However, I see no way around it in the following scenario (unless I’m just really missing something or discovered a bug, which I’m kinda hoping for…).
c is an invalid changeset
iex(4)> Repo.insert(c, [])
{:error, ...}
iex(5)> Repo.transaction(fn -> Repo.insert(c, []) end)
{:ok,
{:error,
...}}
iex(6)> Repo.transaction(fn -> {:ok, _} = Repo.insert(c, []) end)
** (MatchError) no match of right hand side value: {:error, ...}
Ideally there will be additional things in the transaction…but they are based on the inserted records value…I don’t want to wrap everything in a transaction with a try/rescue as well, but I’m not sure how to avoid it.
Also, I’ve glanced at, but don’t quite understand, ecto multi; though I’m not sure that helps if the second db action relies on data from the first.
1 Like
It all just depends on what you’re trying to do. Because I’m not entirely sure what you’re trying to do, here are a few patterns you may find useful.
Try to insert inside a transaction, if it fails, do something else, but let the transaction succeed
Repo.transaction(fn ->
case Repo.insert(changeset) do
{:ok, record} -> handle_success(record)
_ -> do_something_else()
end
end)
Try to insert something, if it succeeds insert something else, and rollback everything if there’s a failure:
Repo.transaction(fn ->
with {:ok, record} <- Repo.insert(foo),
{:ok, other_record} <- Repo.insert(bar) do
{record, other_record}
else
val -> Repo.rollback(val)
end
end)
|> case do
{:ok, {foo, bar}} ->
IO.puts "Both foo and bar were created because the transaction succeedd"
{:error, error} ->
IO.puts "Neither foo nor bar were created because the transaction failed with error: #{inspect error}"
end
6 Likes
Also, if you want to use Multi, Ecto.Multi.merge
can be used to access data from previous operations.
EDIT: actually, using Ecto.Multi.run
might be easier too.
2 Likes
Thank you! I had tried to solve it with ‘with’, but I must have made another mistake in the process. Also, thank you @wojtekmach, I’ll look into multi.merge.
1 Like