Reputation: 15216
I have a Review
model, which schema has belongs_to
User
notation.
Each review should belongs to user, so user_id
column is mandatory.
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
|> a lot of things like validate_length
|> assoc_constraint(:user)
end
And this is my migration:
defmodule MyReelty.Repo.Migrations.AddUserIdToReviews do
use Ecto.Migration
def change do
alter table(:reviews) do
add :user_id, references(:users, on_delete: :nothing)
end
create index(:reviews, [:user_id])
end
end
Unfortunately, when I'm running
%Review{} |> Review.changeset(@valid_params) |> Repo.insert!
review is saved! I double checked there is no user_id
or other user related information in details.
By the way, I checked another stuff like validate_number
it works!
Why does assoc_constraint
doesn't work in this case?
Upvotes: 4
Views: 856
Reputation: 1762
As explained in the doc, cast_assoc
and foreign_key_constraint
rely on the database to check if the foreign constraint is respected or not. In case the constraint is not respected, those functions convert the database error in a changeset error when you try to insert or update.
That is because you need the database to know if the foreign key is valid or not.
The foreign key constraint in only concerned by the fact that user_id
references an existing user. If you try to insert a review containing a non existing user_id
, the insertion will be rejected.
The fact that user_id
should not be null is another subject. It depends if the user_id
field is nullable. By default in Postgres, a field is nullable.
So, as you have noticed, inserting a review without a user_id
is permitted.
If a review must have a related user, you can specify it in your migration.
add :user_id, references(:users, on_delete: :nothing), null: false
In the changeset function, you will use validate_required
to check the field is not null, and cast_assoc
to check it references an existing user.
Upvotes: 1