2015-07-22 3 views
0

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

История событий: Я создаю первичный email для активированных учетных записей и получаю второй new_email, когда пользователь решает изменить свой адрес электронной почты, но еще не подтвердил новый с помощью подтверждения по электронной почте.

Большинство SO поиск дал scopesolution:

Я попытался validates :email, uniqueness: {scope: :new_email} и validates :new_email, uniqueness: {scope: :email} однако я уверен, что эта функция действует, чтобы создать новый ключ среди email1, email2 пары, которая не является желательным эффектом.

В настоящее время я судить справедливость моего кода со следующими два тестовых (которые неудовлетворительными)

test "new_email should not match old email" do 
    @user.new_email = @user.email 
    assert_not @user.valid? 
end 

test "new_email addresses should be unique" do 
    duplicate_user = @user.dup 
    duplicate_user.new_email = @user.email.upcase 
    duplicate_user.email = @user.email + "z" 
    @user.save 
    assert_not duplicate_user.valid? 
end 

ответ

0

Scope не собирается сократить его ... это действительно там, чтобы убедиться, что mail является уникальным среди всех записей, которые могли бы одни и те же new_mail и не поймаешь уникальность для различных new_email значений, и не будет сравнивать значения по две колонки.

Используйте стандартную «уникальность», чтобы избежать дублирования внутри столбца.

Тогда вам нужно создать пользовательскую проверку для кросс колонки ...

validate :emails_unique 

def emails_unique 
    found_user = User.find_by(new_email: email) 
    errors.add(:email, "email is someone's new email") if found_user 
    return unless new_email 
    found_user = User.find_by(email: new_email) 
    errors.add(:new_email, "new email is someone's regular email") if found_user 
end 
+0

Это работало отлично, спасибо за объяснение. –

+0

Как ни странно, мне пришлось добавить '.downcase' в метод' emails_unique', так как встроенный в него один из них имел небольшую лазейку для чувствительности к регистру среди сообщений электронной почты. –

+0

@AlexeiDarmin, если вы хотите, чтобы сравнение было нечувствительным к регистру, вы можете использовать 'LIKE' (в MySQL) или' ILIKE' (в PostgreSQL) – eirikir

0

Я думаю, вы на самом деле просто хотите написать собственный валидатор, что-то вроде этого:

validate :emails_are_unique 

def emails_are_unique 
    if email == new_email 
    errors.add(:base, 'Your new email can not match your old email') 
    end 
end 

Что будет делать то, что вы ищете.

0

validates :email, uniqueness: {scope: :new_email} гарантирует, что email является уникальным среди всех записей с одинаковым значением для new_email. Это не то, что вы хотите.

Вы должны написать пользовательскую функцию проверки и т.д .:

def validate_email_and_new_email_unique 
    if email && self.class.exists?("email = :email OR new_email = :email", email: email) 
    errors.add :email, "must be unique" 
    end 
    if new_email && self.class.exists?("email = :email OR new_email = :email", email: new_email) 
    errors.add :new_email, "must be unique" 
    end 
end 
Смежные вопросы