Duplicate registration how to solve?

I have a registration form, working perfectly.
The only problem I’m experiencing is that it’s allowing you to create multiple users with the same email.

What think it could be?

Controller User

defmodule MyappWeb.UserController do
#
plug Guardian.Plug.EnsureAuthenticated, [handler: UserController] when action in [:index]
#
  def action(conn, _) do
    apply(UserController, action_name(conn),
      [conn, conn.params, current_user(conn)])
  end
#

  def create(conn, %{"user" => user_params}, user) do
    case Registro.create_user(user_params) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "Usuário #{user.nome} criado com sucesso.")
        |> redirect(to: user_path(conn, :show, user))
      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset, user: user)
    end
  end
#

end

Model User

defmodule Myapp.Registro.User do
#
#
  def changeset(user, attrs) do
    user
    |> cast(attrs, [:nome, :email, :password, :plano_user, :status_user, :is_admin])
    |> validate_required([:nome, :email])
    |> validate_format(:email, ~r/@/, message: "E-mail incorreto!")
    |> validate_length(:password, min: 6, message: "Senha inferior a 6 dígitos")
    |> validate_confirmation(:password, message: "Senha não confere!")
    |> unique_constraint(:email)
    |> encrypt_password
  end
#
end

ecto create

defmodule Myapp.Repo.Migrations.CreateUsers do
  use Ecto.Migration

  def change do
    create table(:users) do
      add :nome, :string
      add :email, :string
      add :hash_password, :string
      add :plano_user, :string
      add :status_user, :string, default: 1, null: false
      add :is_admin, :boolean, default: false, null: false

      timestamps()
    end

  end
end

You have to create a unique index and then use Ecto.Changeset.unique_constraint/2. This link also guides you through what is required to do this.

Here is another guide: Making a field unique in ecto.

Edit:

Ah I didn’t notice you were already using unique_constraint/2. Did you migrate your schema to have the unique index for email?

1 Like

From unique_constraint docs

in order to use the uniqueness constraint, the first step is to define the unique index in a migration:

create unique_index(:users, [:email])

Now that a constraint exists, when modifying users, we could annotate the changeset with unique constraint so Ecto knows how to convert it into an error message:

cast(user, params, [:email])
|> unique_constraint(:email)

So you need to to add in your migration

create unique_index(:users, [:email])

Also make sure your email field in database is case insensitive. If you use postgresql make email a :citext instead of :string

1 Like

It really was all that was missing.
Thank you all.
@voger @ryh