Уникальная проблема с паранойей

У меня есть приложение рельсы, в котором я использую драгоценные камни devise и паранойи.
У меня есть таблица пользователей в postgres db, которая имеет уникальную проверку по столбцу электронной почты. Я использую паранойю для мягкого удаления, проблема в том, что когда я удаляю пользователя, а затем пытаюсь создать пользователя, используя электронную почту удаленного пользователя, он выдает ошибку PG::UniqueViolation: ERROR,
Я читал об этом и знаю, что это можно решить с помощью функции частичного индекса рельсов.

http://scottsmerchek.com/2015/08/03/taking-the-d-out-of-crud/

https://devcenter.heroku.com/articles/postgresql-indexes

Как мне это реализовать?
Извините за плохое форматирование, набрав с мобильного телефона.

4 ответа

Поскольку вы удалили пользователя как мягкое удаление, чтобы электронная почта не удалялась из базы данных, только атрибут пользователя is_deleted был установлен в true.

Разрешить PG::UniqueViolation: ERROR Теперь вы должны создать уникальный индекс как для поля email, так и для удаленного_этапа. Таким образом, ваша миграция будет

class AddUniqueIndexToUsers < ActiveRecord::Migration
  def change
    remove_index :users, column: :email
    add_index :users, [:email, :deleted_at], unique: true
  end
end

Это не удастся на Postgresql, возможное решение будет

      class AddUniqueIndexToUsers < ActiveRecord::Migration
  def change
    remove_index :users, column: :email
    add_index :users, [:email, :deleted_at], unique: true, where: "deleted_at is null"
  end
end

См. Https://www.ironin.it/blog/partial-unique-indexes-in-postgresql-and-rails.html

достаточно:

      class AddUniqueIndexToUsers < ActiveRecord::Migration
  def change
    remove_index :users, column: :email
    add_index :users, :email, unique: true, where: 'deleted_at IS NULL'
  end
end

Ответ Ракеша неверен и допускает дублирование в базе данных, потому что соединение UNIQUE index завершится ошибкой, если одно из значений равно (и есть по умолчанию).

Чтобы это работало, вам действительно нужно использовать этот нюанс с уникальными индексами наоборот, вы можете иметь целочисленный столбец, например acive:tinyint (default 1) и составной индекс вроде этого:

      add_index :users, [:email, :active], unique: true

При создании новых пользователей никаких специальных действий не требуется, так как столбец имеет значение по умолчанию 1. Но каждый раз, когда вы удаляете запись, помимо установки deleted_at вам также необходимо установить значение NULL. Таким образом, у вас может быть только одна активная запись и множество удаленных с одного и того же адреса электронной почты.

В PostgreSQL или MySQL> 8.0.13 вы можете работать без этого дополнительного столбца и использовать такой функциональный индекс:

      CREATE UNIQUE INDEX unique_email
                 ON users (email, (IF(deleted_at IS NULL, 1, NULL)));

Результат будет аналогичен примеру с activeстолбец. Как только запись будет удалена, уникальный индекс перестанет работать для этой записи, что позволит вам иметь несколько удаленных записей с одним и тем же email.

Другие вопросы по тегам