Alex Antonov
Alex Antonov

Reputation: 15216

Ecto assoc_constraint doesn't work

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

Answers (2)

Istopopoki
Istopopoki

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

Alex Antonov
Alex Antonov

Reputation: 15216

You have to add user_id to @required_fields, that's it

Upvotes: 2

Related Questions