user2158382
user2158382

Reputation: 4510

Ruby On Rails Devise: How can I avoid duplicate usernames during sign up

Hi I am very new to Ruby on Rails and Devise, and I would like to know how I can configure devise to disallow a user from signing up with a username that is already taken. The initial configuration is to not allow a taken email during signup, but I want this same configuration for my newly created username field. I already added

config.authentication_keys = [ :username ]

into my devise.rb file, but it does not solve my problem

Upvotes: 1

Views: 1759

Answers (2)

Chris Aitchison
Chris Aitchison

Reputation: 4654

If need the name to be unique, regardless of case you need to do this

validates_uniqueness_of :username, case_sensitive: false

This is assuming you don't want one user named 'Bob' and another user named 'bob'.

Also, Rails cannot reliably validate uniqueness on an attribute due to a race condition when it makes the check. You must add a unique database index in order to ensure data integrity.

#postgresql
execute 'CREATE UNIQUE INDEX ON USERS lower(username);'

The reason Rails cannot do a unique validation is because it does the validation like this:

SELECT 1 FROM users WHERE lower(username) = 'bob'
# if nothing found
INSERT INTO USERS ...

But if there is more than one Rails process, which there nearly always will be in production (eg. each Unicorn worker is a process), then a race condition is created where if two processes try to add 'bob' at the same time, then the code may execute such that the first SELECT returns no results for both of them. They would then both try to INSERT at around the same time, and the only thing that will save your data integrity at that point is a unique database index.

Upvotes: 3

user985723
user985723

Reputation: 628

Add this into user.rb:

validates_uniqueness_of :username

Source: http://guides.rubyonrails.org/active_record_validations_callbacks.html#uniqueness

Upvotes: 2

Related Questions