#ruby-on-rails #ruby
Вопрос:
Я нормализую адреса электронной почты в before_validation
, например:
class User before_validation do self.email = normalized_email end def normalized_email User.normalize_email(email) end end
Но тогда я должен делать User.find_by(email: User.normalize_email(params[:email]))
это везде, например, и сегодня меня укусило, когда я пытался найти пользователя, я забыл нормализовать адрес электронной почты, поэтому я хотел бы, чтобы это делалось автоматически.
В идеале я бы не перезаписывал find_by
, и это работало бы для всех методов, например where
, например.
Как я могу это сделать?
Ответ №1:
Я бы просто определил специальный метод для этого варианта использования:
class User def self.by_email(email) find_by(email: User.normalize_email(email)) end before_validation do self.email = normalized_email end def normalized_email User.normalize_email(email) end end
Который затем можно использовать следующим образом:
User.by_email(params[:email])
Пожалуйста, обратите внимание, что я явно не предлагал использовать a scope
для этого, потому что по соглашению области должны быть цепными и, следовательно, должны возвращать ActiveRecord::Relations
то, что плохо работает, когда вы хотите вернуть только одну запись.
Ответ №2:
Вы можете переопределить find_by
пользователя, чтобы это происходило последовательно.
class lt;lt; self def find_by(*args) # find_by can be called without a Hash, make sure. attrs = args.first super unless attrs.is_a?(Hash) # Cover both calling styles, find_by(email: ...) and find_by("email": ...) [:email, "email"].each do |key| # Be careful to not add email: nil to the query. attrs[key] = normalized_email(attrs[key]) if attrs.key?(key) end super end end
Это также охватывает find_by!
, find_or_*
, и create_or_find_by*
методы. Он не охватывает where
ни необработанный SQL.
Вы могли бы переопределить where
, но происходит какое-то странное кэширование, что создает проблемы.
Ответ №3:
Не идеально, но вот что я сделал:
scope :by_email, lambda { |email| where(email: Normalizer.normalize_email(email)) } User.kept.by_email(email).first User.by_email(email).first!
Правка: Удалил мой патч обезьяны, он все равно не работал
Комментарии:
1. Я бы не рекомендовал обезьянам исправлять сам ActiveRecord; он оказывает глобальное влияние за пределами ваших моделей. Вместо этого поместите его в ApplicationRecord, который сам наследуется от ActiveRecord::Base, и сделайте так, чтобы все ваши модели наследовались от ApplicationRecord. Кроме того,
where!
это не документированный метод. Будьте осторожны, полагаясь на это. Обязательно протестируйте его, чтобы знать, не нарушит ли будущая версия Rails ваше предположение. Тебе было бы безопаснее перекрыватьwhere
. Наконец, поскольку это влияет на каждую модель, вы должны убедиться, что каждая модель нормализует свои электронные письма. Если нет, поместите его только в те модели, которые нормализуют их электронную почту.2. да, патч обезьяны все равно не работал, все равно решение области действия не устраняет мои проблемы, а перегрузка where или find_by не работает в отношениях, мех