require 'digest/sha1' require 'email_validator' module Clearance module User extend ActiveSupport::Concern included do attr_accessor :password_changing attr_reader :password include Validations include Callbacks include( Clearance.configuration.password_strategy || Clearance::PasswordStrategies::BCrypt ) end module ClassMethods def authenticate(email, password) if user = find_by_normalized_email(email) if user.authenticated? password return user end end end def find_by_normalized_email(email) find_by_email normalize_email(email) end def normalize_email(email) email.to_s.downcase.gsub(/\s+/, "") end end module Validations extend ActiveSupport::Concern included do validates :email, email: true, presence: true, uniqueness: { allow_blank: true }, unless: :email_optional? validates :password, presence: true, unless: :password_optional? end end module Callbacks extend ActiveSupport::Concern included do before_validation :normalize_email before_create :generate_remember_token end end def forgot_password! generate_confirmation_token save :validate => false end def reset_remember_token! generate_remember_token save :validate => false end def update_password(new_password) self.password_changing = true self.password = new_password if valid? self.confirmation_token = nil generate_remember_token end save end private def normalize_email self.email = self.class.normalize_email(email) end def email_optional? false end def generate_confirmation_token self.confirmation_token = SecureRandom.hex(20).encode('UTF-8') end def generate_remember_token self.remember_token = SecureRandom.hex(20).encode('UTF-8') end def password_optional? encrypted_password.present? && password.blank? && password_changing.blank? end end end