Reputation: 4510
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
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
Reputation: 628
Add this into user.rb:
validates_uniqueness_of :username
Source: http://guides.rubyonrails.org/active_record_validations_callbacks.html#uniqueness
Upvotes: 2