Есть ли лучший способ условно разрешить пользователю войти в систему с «именем пользователя» или «электронной почтой» с ruby на рельсах? - PullRequest
0 голосов
/ 17 апреля 2020

Я смог разрешить пользователям входить в систему либо под своим именем пользователя, либо по электронной почте, применив этот бит кода в проблемах моей модели.

module ClassMethods
    def authenticate(username, email, password)
      user = User.find_by(username: username)
      user_email = User.find_by(email: email)
      return unless user || user_email

      if user
        user.send :new_token
        user.authenticate password
      elsif user_email
        user_email.send :new_token
        user_email.authenticate password
      end
    end
  end

  included do
    has_secure_password
    before_create :set_token
    after_find :fix_up_token
    validates :email, uniqueness: true
    validates :email, presence: true
    validates :username, uniqueness: true
    validates :username, presence: true
    validates :password_confirmation, presence: true, on: :create
  end

Я изначально пытался создать условие для пользователя 'с методом find_by, но мне не повезло. Я закончил с идеей создания 'user_email' как обходного пути, и это работает, но я чувствую, что должен быть способ сделать это с одной переменной.

Обновление

Я смог заставить его работать с двумя ответами ниже.

Этот здесь от max :

def authenticate(username, email, password)
      user = User.where(email: email)
                 .or(User.where(username: username)).take
      return unless user

      user.send :new_token
      user.authenticate password
    end

И этот здесь от Саджад Умар :

def authenticate(username, email, password)
      user = User.find_by(username: username) || User.find_by(email: email)
      return if user.blank?

      user.send :new_token
      user.authenticate password
    end

Обновление 2

Шон рекомендуется использовать регулярное выражение для сканирования ввода для электронной почты формат. У меня уже есть требование к формату электронной почты, но я хотел убедиться, что пользователь не может создать имя пользователя, совпадающее с адресом электронной почты другого пользователя. Итак, я установил валидацию формата для имени пользователя с помощью регулярных выражений.

included do
    has_secure_password
    before_create :set_token
    after_find :fix_up_token
    validates :email, uniqueness: true
    validates :email, presence: true
    validates :username, uniqueness: true
    validates :username, presence: true
    validates :username, format: { with: /\A[a-zA-Z0-9]+\z/,
                                   message: 'only allows letters and numbers' }
    validates :password_confirmation, presence: true, on: :create
  end

Спасибо всем за помощь!

Ответы [ 3 ]

3 голосов
/ 17 апреля 2020

Просто используйте where для создания запроса с предложением или:

def authenticate(identifier, password)
  user = User.where(email: identifier)
             .or(User.where(username: identifier)).take
  return unless user
  user.new_token 
  user.authenticate password
end
1 голос
/ 17 апреля 2020

Вы можете упростить метод authenticate следующим образом

def authenticate(username, email, password)
   user = User.find_by(username: username) || User.find_by(email: email)
   return if user.blank?

   user.send :new_token
   user.authenticate password
end

Это имеет два преимущества по сравнению с вашим кодом

  1. Если пользователь найден с именем пользователя, запрос не будет найти пользователя по адресу электронной почты
  2. без повторения кода

И я не рекомендую использовать предложение where, поскольку оно будет искать всю таблицу и возвращать коллекцию , Принимая во внимание, что метод find_by вернет первый соответствующий объект.

1 голос
/ 17 апреля 2020

Предполагая, что ваши имена пользователей не могут быть отформатированы как электронные письма, я бы порекомендовал использовать регулярное выражение для сканирования ввода на наличие формата электронной почты, и следуя логи "input is email" c, если это так, в противном случае следуйте "input is username" .

Пример взят из этого SO ответа :

def authenticate(username_or_email, password)
  user = get_user(username_or_email)

  return if user.nil?

  user.send :new_token
  user.authenticate password
end

def get_user(username_or_email)
  if is_email?(username_or_email)
    User.find_by(email: username_or_email)
  else
    User.find_by(username: username_or_email)
  end
end

def is_email?(string)
  email_regex = /\A(\S+)@(.+)\.(\S+)\z/

  return true if string ~= email_regex

  false
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...