How to use Complex Constraint in Ecto?

This is what I want to implement

  1. Customer can create a contact with name and phone number.
    2, Customer can not create a contact with already existing phone number.

So I did like this…

  schema "people" do
    field :name, :string
    field :phone_number, :string
    belongs_to :phonebook, Phonebook

    timestamps()
  end

  def changeset(%Person{} = person, attrs) do
    person
    |> cast(attrs, [:name, :phone_number])
    |> validate_required([:name, :phone_number])
    |> unique_constraint(:phone_number)
  end

and in migration file

create unique_index(:people, [:phone_number)

But other customer can not create a contact with same number because other customer may has a same number.
So what is solution for this? I looked up Ecto document and found https://hexdocs.pm/ecto/Ecto.Changeset.html#unique_constraint/3

Complex Constraints

is this correct solution?
I have tried this as documented, but it won’t work.

What does your migration look like for the people table?

 def change do
    alter table(:people) do
      modify :phone_number, :citext
    end

    create unique_index(:people, [:phone_number])
  end

here it is

So as I understand you, each phone number may only used once per phone book?

So create the unique index like this:

create unique_index(:people, [:phone_number, :phone book])

And then set the constraint in the changeset accordingly. It is the exact same situation as described in the complex constraint section you linked. It’s just that your names are a bit different.

1 Like

A small note, using :citext for a phone_number field is quite strange.

1 Like
schema "people" do
        field :name, :string
        field :phone_number, :string
        belongs_to :phonebook, Phonebook

        timestamps()
  end

people schema doesn’t have :phonebook field do you mean :phonebook_id in this?

`

create unique_index(:people, [:phone_number, :phone book])

`

oh I see, I will change it to string
Thanks

Ok guys! thanks for your help.
@NobbZ I did it like in migration

create unique_index(:people, [:phone_number, :phonebook_id])

and in changeset,

|> unique_constraint(:phone_number, name: :people_phone_number_phonebook_id_index)

Thanks!