Devise: Allow users to register as “UsErNaMe” but login with “username”
-
07-06-2021 - |
Question
In the same way most websites work, I was to store "UsErNaMe" in the database but let users login with "username".
This is a fairly obvious and necessary feature, and plenty of people seem to have asked it, but the solution I keep stumbling upon seems disconnected from Devise's own documentation.
For instance, consider this blog post: http://anti-pattern.com/2011/5/16/case-insensitive-keys-with-devise
[...]you’ve probably run into the problem that some users like to type certain letters in their logins (email and/or username) in uppercase, but expect it to be case-insensitive when they try to sign in. A not unreasonable request[...]
Cool! That's what I want.
His solution:
# config/initializers/devise.rb
Devise.setup do |config|
config.case_insensitive_keys = [:email, :username]
end
That's the solution I keep finding. But here's the documentation for that config option:
# 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 ]
In particular: "These keys will be downcased upon creating/modifying a user." In other words, the username is being downcased in the database.
To verify:
User.create username: "UsErNaMe", password: "secret", email: "email@com.com"
#=> <User username="username"...>
Am I missing something painfully obvious?
Solution
From devise wiki: you need to overwrite devise's find_first_by_auth_conditions
method in your model.
ActiveRecord example:
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
You can remove OR lower(email) = :value
part if you don't need auth by email too.
That way you don't need to list username
in case_insensitive_keys
and it wouldn't be downcased in the database.