Несколько вещей, которые я бы изменил в проверке:
Выполните проверки наличия, уникальности и формата в отдельных проверках. (Ваш ключ уникальности в хэше атрибутов, который вы передаете "validates", перезаписывается в вашей проверке). Я хотел бы, чтобы это выглядело больше как:
validates_uniqueness_of: электронная почта,: scope =>: местоположение
validates_presence_of: электронная почта
validates_format_of: email,: with => RFC_822 # Мы используем глобальные регулярные выражения проверки
Проверки - это уровень приложения, одна из причин, по которой вы должны их разделить, заключается в том, что проверки наличия и формата можно выполнять, не касаясь базы данных. Проверка уникальности коснется базы данных, но не будет использовать уникальный индекс, который вы настроили. Проверки уровня приложения не взаимодействуют с внутренними компонентами базы данных, они генерируют SQL и на основании результатов запроса определяют достоверность. Вы можете оставить validates_uniqueness_of, но будьте готовы к условиям гонки в вашей заявке.
Поскольку проверка выполняется на уровне приложения, она будет запрашивать строку (что-то вроде "SELECT * FROM subscription WHERE email = 'email_address' LIMIT 1" ), если строка возвращается, проверка завершается неудачно. Если строка не возвращается, она считается действительной.
Однако, если в то же самое время кто-то другой регистрируется с тем же адресом электронной почты, и они оба не возвращают строку перед созданием нового, то вторая фиксация «сохранения» вызовет ограничение индекса базы данных уникальности, не вызывая проверку в приложении. (Поскольку, скорее всего, они работают на разных серверах приложений или, по крайней мере, на разных виртуальных машинах или процессах).
ActiveRecord :: RecordInvalid возникает при сбое проверки, а не при нарушении ограничения уникального индекса для базы данных. (Существует несколько уровней исключений ActiveRecord, которые могут запускаться в разные моменты жизненного цикла запроса / ответа)
RecordInvalid вызывается на первом уровне (уровень приложения), тогда как RecordNotUnique может быть вызвано после попытки отправки, и сервер базы данных определяет, что транзакция не соответствует ограничению индекса. ( ActiveRecord :: StatementInvalid является родителем исключения после выборки, которое будет сгенерировано в этом экземпляре, и вы должны его спасти, если вы действительно пытаетесь получить обратную связь с базой данных, а не проверку уровня приложения)
Если вы находитесь в вашем контроллере "rescue_from" (как обрисовано в общих чертах у The Who), должно нормально работать для восстановления после этих различных типов ошибок, и похоже, что первоначальное намерение было обрабатывать их по-разному, Вы можете сделать это с помощью нескольких "rescue_from" вызовов.