нормализуйте электронную почту при выполнении find_by(электронная почта: …)

#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 не работает в отношениях, мех