Уникальная проверка для одного столбца и условие для второго столбца на основе значения строки

#ruby-on-rails #postgresql #ruby-on-rails-5

#ruby-on-rails #postgresql #ruby-on-rails-5

Вопрос:

У меня есть база данных, в которой электронная почта установлена как уникальная проверка со статусом. Я установил область видимости как значение int ‘status’, которое равно 1, когда активна конкретная учетная запись. Поэтому, если пользователь переключает свою страну, статус его учетной записи переключается на 0, и создается новая учетная запись с тем же адресом электронной почты, а статус устанавливается равным 1. Поэтому, чтобы решить эту проблему, я использовал составной уникальный ключ для «электронной почты» и «статуса» как,

 validates :email, uniqueness: { scope: :status }
 

Итак, давайте проведем небольшой пробный запуск.
в настоящее время пользователь находится в стране X, и его адрес электронной почты abc@xyz.com
таким образом, база данных может выглядеть так

 email: abc@xyz.com
status: 1
 

Теперь, если он переходит к
обновлениям базы данных country Y как,

 [for company X]
email: abc@xyz.com
status: 0
[for company Y]
email:abc@xyz.com
status: 1
 

работает нормально
, но теперь, если наш путешественник отправится в страну Z,
база данных застрянет, как и сейчас, статус компании Y обновится до 0, и поскольку теперь эта комбинация не уникальна, поэтому вернет ошибку.
Также сложная задача здесь использовать только email и status в качестве ключей.
Чего я хочу добиться, так это того, что для определенного статуса электронной почты: 1 должно быть уникальным, а статус: 0 может быть любым количеством раз.
Итак, я пытался сформулировать оператор следующим образом

 validates :email, uniqueness: { scope: :status }, if: :status == 1
 

но не повезло, так как я не могу принять значение статуса конкретного пользователя в модели.
Заранее спасибо!!
PS: Я новичок в ROR, поэтому предоставьте соответствующие ссылки, чтобы я мог узнать больше xD.

Ответ №1:

Возможно, вы захотите пересмотреть структуру своей базы данных.

Но одно из решений состоит в том, чтобы сделать:

 validates_uniqueness_of :email, scope: :status, if: :active?

def active?
  status == 1
end
 

Проверьте api для этой проверки здесь .

Но я настоятельно рекомендую вам переделать структуру базы данных, чтобы предотвратить это на уровне базы данных. Что-то вроде:

 inactive_emails table
email              |    company
--------------------------------
one@exmaple.com    |     A
one@example.com    |     B
one@example.com    |     C
two@example.com    |     A


active_emails table
email              |    company
--------------------------------
one@example.com    |      D
two@example.com    |      E
 

Для модели неактивных электронных писем вы могли бы:

 class InactiveEmails
  validates_uniqueness_of :email, scope: :company
end
 

И для модели активных электронных писем:

 class ActiveEmails
  validates_uniqueness_of :emails, scope: :company
end
 

Таким образом, вы гарантируете, что у каждой компании есть уникальные активные электронные письма, и каждое электронное письмо может быть активным только для одной компании одновременно.

Теперь вам нужно переключать электронные письма между двумя таблицами. Вы могли бы использовать обратный вызов, например:

 before_save :check_if_email_is_inactive_for_company

def check_if_email_is_inactive_for_company
  if InactiveEmail.where(email: email, company: company).exists?
    # remove from inactive? or inform user this email was deactivated before?
  end
end
 

Страница Rails API — ваш друг.

Ответ №2:

Вы можете решить свою проблему многими способами, но я расскажу 2 способа

  1. Вы можете применить область действия следующим образом
     validates :email, uniqueness: { scope: [:status,:country]}  
     
  2. Если вы хотите обработать его с помощью области видимости для одного поля
     validates :email, uniqueness: { scope: :status }, unless: lambda{ |user| user.status == 0 }
     

Если идентификатор пользователя равен x, приведенная выше проверка позволяет использовать идентификатор пользователя: x, статус: 0 несколько раз, но у вас может быть только одна комбинация user_id: x, статус 1.