I’m using Ecto.Repo.insert_all/3 and I’d like to gracefully handle foreign key errors.
Explanatory code:
def insert_post(body, user_id) do
Repo.insert_all(Post, [%{body: body, user_id: user_id}])
end
If the user_id does not exist in the users table then a Postgrex.Error is raised but I’d like to convert this to an error. With Ecto.Repo.insert/2 this is handled by adding a foreign key constraint, but since insert_all is lower-level this needs to be handled manually, which I understand. But I’d like to be able to handle it easier than this:
def insert_post(body, user_id) do
Repo.insert_all(Post, [%{body: body, user_id: user_id}])
rescue
e in Postgrex.Error ->
if e.postgres.constraint == "posts_user_id_fkey" do
{:error, "user does not exist"}
else
raise e
end
end
From the reply quoted below on a related topic - which you should totally have a look on, you may use assoc_constraint/3 or foreign_constraint/3. For a more generic approach, instead of manually calling any of these functions or any other validation you might want to add like cast/4, I would recommend you do something like:
defmodule Post do
use Ecto.Schema
import Ecto.Changeset
schema "post" do
# ...
end
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:user_id])
|> foreign_key_constraint(:user_id)
end
end
###
params = %{body: body, user_id: user_id}
%Post{}
|> Post.changeset(params)
|> Repo.insert # {:ok, Ecto.Schema.t} | {:error, Ecto.Changeset.t}