I’m using Ecto (2.2.8) to work with an existent PostgreSQL
database.
I defined two schemas to represent owner
and house
. The house
schema has a FK (belongs_to
) owner
. I defined a schema and a changeset for house
that look as follows:
@primary_key {:id, :id, autogenerate: true}
schema "house" do
belongs_to :owner, Owner, foreign_key: :owner_id
field :name, :string
end
def changeset(house, params \\ %{}) do
house
|> cast(params, [:name, :owner_id])
|> validate_required([:owner_id])
|> foreign_key_constraint(:owner_id)
end
The Problem
I expected the following code to return a tuple {:error, changeset}
, when there isn’t a owner
record with id
10
in database:
House.changeset(%House{}, %{name: "Whatever", owner_id: 10}) |> Repo.insert
However, I’m getting a Postgrex.Error:
** (Postgrex.Error) ERROR 23503 (foreign_key_violation): insert or update on table "house" violates foreign key constraint "house_owner_id_fkey"
.
If I check the content of changeset.constraints
before calling Repo.insert
, this is what I get:
House.changeset(%House{}, %{name: "Whatever", owner_id: 10})
|> Map.get(:constraints)
[
%{
constraint: "house_owner_id_fkey",
error: {"does not exist", []},
field: :owner_id,
match: :exact,
type: :foreign_key
}
]
So, when using foreign_key_constraint
shouldn’t I get a tuple {:error, changeset}
that I can pattern match as the docs suggests?
This question was originally posted on StackOverflow, but someone at Slack suggested me to post it here: https://stackoverflow.com/questions/48425959/ecto-insert-changeset-with-foreign-key-constraint-raise-postgrex-error