Сегодня, занимаясь разработкой одного Ruby on Rails проекта обнаружил странную особенность: падают две spec-и. Ни у кого в проекте не падают, а у меня — падают. Код, gem-ы, система и софт один и тот же, только у меня спеки падают, а у других участников проекта — нет.
Для того, чтобы разобраться полез вглубь кода. Причина того, что не проходит спека — неверная обработка нарушения уникальности индекса в базе данных. Стоп, ведь спека и проверяет эту ситуацию, как же так. Иду в блок обработки ошибок, да, так и есть, перехватывается и корректно обрабатывается исключение ActiveRecord::RecordNotUnique, которое ActiveRecord выбрасывает при попытке вставить неуникальное значение в таблицу с unique-индексом. Смотрим как генерация данного исключения реализована в ActiveRecord для PostgreSQL:
Как можно заметить, генерация того или иного исключения происходит в зависимости от возвращаемого базой сообщения об ошибке. И тут все встает на свои места: у меня в настройках PostgreSQL (файл /etc/postgresql/8.4/main/postgresql.conf) выставлена такая опция:lc_messages = 'ru_RU.UTF-8' # locale for system error message
и вместо ожидаемого «duplicate key value violates unique constraint» база возвращает локализованное: «дублирующее значение ключа нарушает условие уникальности», что приводит к генерации совсем другого исключения, а следовательно, рушит весь код.
Итак, кто виноват и что делать? В моем случае достаточно поменять локализацию сообщений об ошибках в конфиге PosgreSQL. Но вообще, в rails-коде по-возможности лучше добавить валидацию на уникальность в модель (validate :field, :uniqueness => true) и не формировать логику работы приложения на основе типа исключений от базы данных.