Попросили шифровать в базе телефоны и email клиентов. Включила encrypts :phone в модели, ключи сделала через bin/rails db:encryption:init, положила в credentials. Шифрует, расшифровывает, а Customer.find_by(phone: params[:phone]) теперь всегда nil. Поддержка ищет по телефону каждый день. Что я упускаю?
По умолчанию шифрование недетерминированное: одна и та же строка каждый раз шифруется по-разному, искать по ней нельзя в принципе. Для полей, по которым ищешь, есть deterministic: true:
class Customer < ApplicationRecord
encrypts :phone, deterministic: true
encrypts :email, deterministic: true, downcase: true
encrypts :comment
end
Customer.find_by(phone: params[:phone]) # теперь находит
Цена понятная: одинаковые телефоны дают одинаковый шифротекст, по базе видно, что у двух клиентов один номер. Для телефона и email обычно приемлемо, для свободного текста нет, его оставь как есть.
Ещё две вещи. Номер нормализуй до шифрования, иначе «+7 911» и «8911» станут разными строками и поиск снова сломается. И колонку сделай пошире, шифротекст заметно длиннее исходного, в varchar(20) не влезет. Уже зашифрованные записи после смены на deterministic придётся перешифровать через find_each и encrypt.
LIKE по зашифрованному полю не работает даже с deterministic. Ищут по последним цифрам, значит, хвост номера отдельной колонкой
Нормализовать пока можно в before_validation. В main уже лежит normalizes, обещают в 7.1, будет одной строкой