Разработать: разрешить пользователям регистрироваться как "UsErNaMe", но войти с "username"

Так же, как и большинство веб-сайтов, я должен был хранить "UsErNaMe" в базе данных, но позволить пользователям войти в систему с "именем пользователя".

Это довольно очевидная и необходимая функция, и многие люди, похоже, ее просили, но решение, которое я продолжаю спотыкаться, кажется, отключено от собственной документации Devise.

Например, рассмотрите это сообщение в блоге: http://anti-pattern.com/2011/5/16/case-insensitive-keys-with-devise

[...] Вероятно, вы столкнулись с проблемой, которую некоторые пользователи любят печатать определенные буквы в их логинах (адрес электронной почты и/или имя пользователя) в верхнем регистре, но ожидайте, что он будет нечувствителен к регистру, когда они попытаются войти. необоснованный запрос [...]

Круто! Это то, что я хочу.

Его решение:

# config/initializers/devise.rb
Devise.setup do |config|
  config.case_insensitive_keys = [:email, :username]
end

Это решение, которое я все время нахожу. Но вот документация для этого варианта конфигурации:

# Configure which authentication keys should be case-insensitive.
# These keys will be downcased upon creating or modifying a user and when used
# to authenticate or find a user. Default is :email.
config.case_insensitive_keys = [ :username, :email ]

В частности: "Эти клавиши будут удалены при создании/изменении пользователя". Другими словами, имя пользователя сбрасывается в базу данных.

Чтобы проверить:

User.create username: "UsErNaMe", password: "secret", email: "[email protected]"
#=> <User username="username"...>

Я пропустил что-то больно очевидное?

Ответ 1

Из devile wiki: вам нужно перезаписать метод find_first_by_auth_conditions в вашей модели.

Пример ActiveRecord:

def self.find_first_by_auth_conditions(warden_conditions)
  conditions = warden_conditions.dup
  if login = conditions.delete(:login)
    where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
  else
    where(conditions).first
  end
end

Вы можете удалить часть OR lower(email) = :value, если вам также не нужна авторизация по электронной почте.

Таким образом, вам не нужно перечислять username в case_insensitive_keys, и он не будет удален в базе данных.