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?
Update:
I'm not using Ecto's migrations. The database tables are already created and migrations are handled by a different project. The SQL Schema look like this:
Column | Type | Modifiers
---------------+---------+-------------------------------------------------------
id | integer | not null default nextval('house_id_seq'::regclass)
owner_id | integer | not null
Indexes:
"house_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"house_owner_id_fkey" FOREIGN KEY (owner_id) REFERENCES owner(id) DEFERRABLE INITIALLY DEFERRED