Reputation: 159
We have over 29K users in our database. "User" is one of our tables and has a unique field "email" with an index defined in one of our migrations:
#3434324_devise_create_user.rb
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
t.string :email, :null => false, :default => ""
end
add_index :users, :email, :unique => true
end
end
We don't have any issues creating users... for the most part. However, with some emails (potentially those that have been previously deleted from the DB at one point or where created long time ago), we are encountering a rare issue:
We can't create them because the "unique" validation fails, however, there is not a single user with that email.
This is an example of what is happening (which does not make any sense if you ask me).
When we try to create a user with the email "[email protected]":
$ p = Devise.friendly_token[0,20]
$ User.create!({email: "[email protected]", password: p})
We get the following result:
(11.6ms) BEGIN
User Exists (11.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1
(10.3ms) ROLLBACK
ActiveRecord::RecordInvalid: Validation failed: Email has already been taken
from /Users/example/.rvm/gems/ruby-2.0.0-p451@example/gems/activerecord-4.1.6/lib/active_record/validations.rb:57:in `save!'
At the same time, if we look for that email in the database:
$ User.find_by_email("[email protected]")
It does not exist!
User Load (12.7ms) SELECT "users".* FROM "users" WHERE "users"."disabled" = 'f' AND "users"."email" = '[email protected]' LIMIT 1
=> nil
Does this make sense for any of you?
Upvotes: 0
Views: 133
Reputation: 84124
There is a big difference between the query you get when you run User.find_by_email
and the one that is run by the validation: the former has an extra condition on the disabled
column. It would seem that when you've been deleting using you've just be flagging them as deleted rather than actually removing.
Given what you've posted I can't tell where that is coming from (perhaps a default scope or an extension to rails) but it would certainly account for the difference in results. You could confirm this by searching for the user in the psql shell.
You could change the validation to ignore these disabled rows:
validates_uniqueness_of :email, conditions: -> { where(disabled: false) }
However you still wouldn't be able to create this user since the unique index on email would prevent this. If you want to able to have multiple users with the same email (but only one that is not disabled) you would have to make this a multi column index on email and some other attribute that would be different for all the "old" users but would be the same for active users
Upvotes: 1