Каждый рубист, поработавший с Ruby On Rails знаком с ORM ActiveRecord. Обсудим одну из предложенных из коробки валидаций, а именно, валидации на уникальность, и почему database_validations gem спасет консистенцию вашей базы данных.
Допустим, у вас есть модель пользователей с уникальностью на поле email, т.е.
class User < ApplicationRecord
validates :email, uniqueness: true
end
Вы, возможно, уже знаете, что данная валидация выполняет следующий запрос
SELECT 1 FROM users WHERE email = $1
каждый раз, когда мы пытаемся сохранить запись в базу данных.
У данного подхода, есть несколько недостатков:
Во-первых, исполнение дополнительного запроса, и в случае, если в модели инициализировано несколько валидаций на уникальность, запрос будет выполнен на каждую из них. Это не эффективно, а также требует наличие индексов, если мы хотим, чтобы данные запросы исполнялись быстро.
Во-вторых, данное решение не гарантирует уникальность из-за возможной гонки за данными. Несколько конкурентных операций могут одновременно узнать об отсутствии конкретной записи, в следствии чего, сохранить одни и те же данные.
Конечно, редкие случаи с гонкой данных возможно разрешить добавив ограничение на уникальность на уровне базы данных. Но в данном случае, вы не получите ошибку валидации, запрос к БД просто упадет и вся транзакция откатится.
В этой ситуации поможет gem database_validations, который предоставляет совместимость между ограничениями в базе данных и валидациями.
Ознакомившись с документацией и бенчмарками, можно прийти к выводу, что данный gem ускорит процесс сохранения записей в базу данных минимум в два раза.
Благодаря поддержке таких баз данных, как PostgreSQL, SQLite, MySQL и обратной совместимости с validates_uniqueness_of
, процесс замены на validates_db_uniqueness_of
занимает считанные минуты.
Удобный matcher для RSpec также присутствует из коробки:
specify do
expect(described_class)
.to validate_db_uniqueness_of(:field)
.with_message('duplicate')
.with_where('(some_field IS NULL)')
.scoped_to(:another_field)
.with_index(:unique_index)
end
При переходе на новую валидацию, вам необходимо иметь ограничения на уникальность в базе данных, но если их еще нет, gem об этом укажет во время запуска приложения.
Гем протестирован на приложении с 100+ валидациями на уникальность среди 50+ моделей.
Используйте гем и делитесь мнением. Любой вклад в дальнейшее развитие приветствуется!
Автор: djezzzl