Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

case insensitive name, while preserving capitalization, in Devise

Using a name as key, how do we validate the name when registering by ignoring case while still remembering the case when displaying?

In config/initializers/devise.rb, setting config.case_insensitive_keys = [ :name ] seems to lowercase the entire name before registering.

Example: some dude names himself TheFourthMusketeer.

  • The views will display TheFourthMusketeer, not thefourthmusketeer
  • No new user can register under, say, tHEfourthMUSKETEER
like image 339
Clucking Turtle Avatar asked Feb 18 '23 18:02

Clucking Turtle


2 Answers

What you might try is to not set :name as case insensitive, which will properly save the case-sensitive name in the database:

config.case_insensitive_keys = []

Then, override the find_first_by_auth_conditions class method on User to find the user by their name. Note that this code will vary depending on the database (below is using Postgres):

def self.find_first_by_auth_conditions(warden_conditions)
  conditions = warden_conditions.dup
  if login = conditions.delete(:login)
    where(conditions).where("lower(name) = ?", login.downcase).first
  else
    where(conditions).first
  end
end

Doing this, a User.find_for_authentication(login: 'thefourthmusketeer') will properly return the record with a name of "TheFourthMusketeer".

See https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address for an explanation of overriding this method.

like image 130
Dylan Markow Avatar answered Feb 20 '23 06:02

Dylan Markow


The accepted answer is incomplete because it's still case-sensitive on registration. So for example, 'username' and 'USERNAME' could both register successfully, but only the first would be able to login.

Disable case-insensitive keys in config/initializers/devise.rb (this can also be model-specific so check there too):

config.case_insensitive_keys = []

Overwrite the find_first_by_auth_conditions method of models/user.rb:

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

...and also set validates_uniqueness_of in models/user.rb:

validates_uniqueness_of :username, :case_sensitive => false

So there you have it: case-insensitive authentication, with case-insensitive registration, that preserves case, in the database.

like image 20
Adelmar Avatar answered Feb 20 '23 06:02

Adelmar