RoR Devise: Войдите в систему с именем пользователя или по электронной почте

Какой лучший способ разрешить пользователям регистрироваться с их адресом электронной почты или их именем? Я использую warden + devise для аутентификации. Я думаю, что, вероятно, это будет не слишком сложно сделать, но я думаю, мне нужен совет, где можно разместить все необходимое. Возможно, разработка уже предоставляет эту функцию? Как и в config/initializers/devise.rb, вы должны написать:

config.authentication_keys = [ :email, :username ]

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

Username or Email:
[____________________]

Password:
[____________________]

[Sign In]

Ответ 1

Я нашел решение проблемы. Я не совсем доволен этим (я бы предпочел бы указать это в инициализаторе), но теперь он работает. В пользовательской модели я добавил следующий метод:

def self.find_for_database_authentication(conditions={})
  find_by(username: conditions[:email]) || find_by(email: conditions[:email])
end

Как отмечали @sguha и @Chetan, еще один отличный ресурс доступен в официальной вики-разработке.

Ответ 3

def self.find_for_authentication(conditions)
  conditions = ["username = ? or email = ?", conditions[authentication_keys.first], conditions[authentication_keys.first]]
  # raise StandardError, conditions.inspect
  super
end

Используйте свой пример!

Ответ 4

Убедитесь, что вы уже добавили имя пользователя и добавили имя пользователя в attr_accessible. Создайте виртуальный атрибут входа в "Пользователи"

1) Добавить логин как attr_accessor

# Virtual attribute for authenticating by either username or email
# This is in addition to a real persisted field like 'username'
attr_accessor :login

2) Добавить логин в attr_accessible

attr_accessible :login

Скажите, что использовать: login в файлах authentication_keys

Измените config/initializers/devise.rb, чтобы иметь:

config.authentication_keys = [ :login ]

Перезаписать метод find_for_database_authentication в Users

# Overrides the devise method find_for_authentication
# Allow users to Sign In using their username or email address
def self.find_for_authentication(conditions)
  login = conditions.delete(:login)
  where(conditions).where(["username = :value OR email = :value", { :value => login }]).first
end

Обновить список просмотров Удостоверьтесь, что у вас есть представления в вашем проекте, чтобы вы могли их настроить.

remove <%= f.label :email %>
remove <%= f.email_field :email %>
add <%= f.label :login %>   
add <%= f.text_field :login %>

Ответ 5

https://gist.github.com/867932: одно решение для всего. Войдите, забыли пароль, подтверждение, инструкции по разблокировке.

Ответ 6

Platforma Tec (разработчик автор) опубликовал решение своей вики-библиотеки github, которая использует базовую стратегию аутентификации Warden, а не подключается к контроллеру:

https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address

(Более ранний ответ имел сломанную ссылку, которая, как мне кажется, была предназначена для ссылки на этот ресурс.)

Ответ 7

Если вы используете MongoDB (с MongoId), вам нужно запросить по-другому:

  def self.find_for_database_authentication(conditions={})
    self.any_of({name: conditions[:email]},{email: conditions[:email]}).limit(1).first
  end

просто так будет где-то в сети.

Ответ 8

С помощью squeel gem вы можете сделать:

  def self.find_for_authentication(conditions={})
    self.where{(email == conditions[:email]) | (username == conditions[:email])}.first
  end

Ответ 9

Здесь находится решение Rails, которое рефакторирует @padde. Он использует ActiveRecord find_by для упрощения вызовов, обеспечивает только один вызов на основе регулярного выражения, а также поддерживает числовые идентификаторы, если вы хотите разрешить это (полезно для скриптов /API ). Регулярное выражение для электронной почты так же просто, как и должно быть в этом контексте; просто проверяя наличие @, поскольку я предполагаю, что ваш идентификатор имени пользователя не позволяет @символов.

def self.find_for_database_authentication(conditions={})
  email = conditions[:email]
  if email =~ /@/ 
    self.find_by_email(email)
  elsif email.to_s =~ /\A[0-9]+\z/
    self.find(Integer(email))
  else
    self.find_by_username(email])
  end
end

Как и wiki и @aku, я также рекомендую создать новый параметр login с использованием attr_accessible и authentication_keys вместо использования: здесь. (Я сохранил его как: email в этом примере, чтобы показать быстрое исправление.)

Ответ 10

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

 def self.authenticate(email, password)
   user = find_by_email(email) ||
     username = find_by_username(email)
   if user && user.password_hash = BCrypt::Engine.hash_secret(password, user.password_salt)
     user
   else
     nil
   end
end

Ответ 11

Я использую быстрый взлом для этого, чтобы избежать изменения какого-либо кода определенного кода и использовать его для моего конкретного сценария (я особенно использую его для API, где мобильные приложения могут создавать пользователей на сервере).

Я добавил файл before_filter для всех контроллеров разработки, где, если имя пользователя передается, я генерирую электронное письмо от имени пользователя ( "# {params [: user] [: username]} @mycustomdomain.com" ) и сохраняю пользователь. Для всех других вызовов я генерирую электронное письмо на основе той же логики. Мой before_filter выглядит следующим образом:

def generate_email_for_username
    return if(!params[:user][:email].blank? || params[:user][:username].blank?)
    params[:user][:email] = "#{params[:user][:username]}@mycustomdomain.com"
end

Я также сохраняю имя пользователя в таблице users, поэтому я знаю, что пользователи с электронной почтой, заканчивающиеся на @mycustomdomain.com, были созданы с использованием имени пользователя.