Reputation: 187014
I'm writing a script for a big migration and have come across a major issue.
# Import users
user_data.each do |data|
u = User.new
u.id = data.id
u.email = data.email
# more user attributes set...
u.save!
end
# required to prevent Postgres from trying to use now taken user ids
ActiveRecord::Base.connection.execute "ALTER SEQUENCE users_id_seq RESTART WITH #{User.last.id+1};"
So first we read user data from a data source, and set it's id manually. We need to preserve ids since we are migrating associated data as well.
Then later on, we need to create more users conditionally from the data of an associated object.
# Create a user for this email if no user with this email exists.
if data.email
user = User.find_by_email(data.email)
if user
o.user = user
else
o.user = User.create!(
first_name: 'Unknown',
last_name: 'Unknown',
email: data.email,
password: generate_temp_password
)
end
end
This fails at User.create!
with:
Validation failed: Email has already been taken (ActiveRecord::RecordInvalid)
I've debugged this a bit and can see that User.where(email: data.email).first
is nil
right before this error is thrown. I suspect this has something to with setting ids beyond the current auto increment value, somehow causing the new records to be invisible in my queries, but visible to Postgres own validations.
So how can a user with a specific email not be present, but still trigger DB validation errors?
Upvotes: 1
Views: 317
Reputation: 187014
Apparently, Devise downcases email addresses. And the offending email had some caps in it. So it missed a case sensitive check, and then failed as a dupe when case insensitive.
Devise outsmarted me it seems.
Upvotes: 1