Create new user with email as a soft deleted user - mysql

I am using ActsAsParanoid for soft deleting users.After deleting(soft) a user, my client wants to create user with same email id.But it generating unique field error since email column is unique.So my question is can we set the uniqueness for email column only if the deleted_at column is null.
Pls reply if u dont understand my question.

I suppose you could change the uniqueness constraint of your users table to be:
UNIQUE (email, deletion_date)
This would effectively:
For standard (non-deleted) users, guarantee they have unique email addresses, since their deletion dates would presumably all be NULL.
For deleted users, not make any guarantee about email addresses, since they all have unique deletion dates.
For new users, allow them to use an email address that a deleted user has, since the new user will have a NULL deletion date, while the deleted user has a value there.

Ah, just change old email to something like
Me#yourmail.com_deleted
That way if you need to view the old email it's everything before the underscore deleted.
In other words here have new user create new account.
Probably have a mutator in the background add the underscore deleted on the old account.
Underscore deleted just an example.

Related

Best practice store email unique MySQL and Validate JS

I have a table where email is a unique key, the point is... when the user get deleted in the manage form, I do an update, inserting "1" in a column called "deleted", doing this I keep the data and the history of that user... But if I have to add a new user with the same email, Bang MySQL catches me
So.. my question is, the best practice is?
Do a remove in table when user get deleted, losing the history of that user
Remove the unique key in the column email, and keep the validate only in JS for prevent duplicates emails
Another one...
Thanks for your time
You can restrict emails to being unique only if not deleted with a virtual column:
create table user (
email varchar(320),
deleted tinyint,
undeleted_email varchar(320) as (if(deleted,null,email)) unique
);
fiddle
You could reverse the logic and instead of storing a nullable deletion mark, store an active mark. Use a check constraint (in MySQL 8+) or a trigger (in lower MySQL versions which don't enforce check constraints) to restrict the possible values of the active mark to one (non-NULL) value (and NULL). Then put the unique constraint on the e-mail address and the active mark combined. That way you can have multiple rows with the same e-mail address and a NULL active mark but maximally one with that address and a non-NULL active mark.
CREATE TABLE user
(id integer,
email varchar(256),
active tinyint,
PRIMARY KEY (id),
CHECK (active = 1),
UNIQUE (email,
active));
db<>fiddle
But as a non technical side note, check, if you're legally allowed to keep the history of a user when they delete their account according to the data protection laws applying to you. They may have the right to expect that everything is deleted when they delete their account.
And you could also consider, no to create a new account, if a user comes back, but instead offer them to reactivate their old account.

Should I lock the table when creating user?

I want to create a user into User table.
These are my process.
continue when email and nickname are not exist
creates a user
I think if I didn't lock the User table while creating a user then email and nickname can be duplicated.
Any ideas?
Avoid locks where possible. Instead, use a unique index, and simply insert the user. If the user or email exists, your query will return an error similar to:
Error Code: 1062. Duplicate entry 'john.doe#example.org' for key 'unique_email'
This should be done with 2 separate indexes. One for email, and one for users. This has the following advantages, and almost zero disadvantages:
It enforces database consistency. At no point will 2 users have the same email address, nor the same username.
It avoids unnecessary locks.
It avoids technical debt. Let's say down the line you add a user importer. In the importer you fail to check for duplicate accounts, or add in locks, or forget to check if the username or email exists. Your importer will work, and your database will now contain entries that duplicate each other.
I'd try to create a combined unique key on email and nickname
CREATE UNIQUE INDEX some_index_name ON user_table(email , nickname)
Edit: To address the comments below, we should as well create 2 more unique indexes for email and username, to make sure 2 users with separate emails can share the same username and vice versa.

User table structure for registration and login system with email

I want to know what is best table structure and indexes for users table (login by email and password) for best performance.
I don't want to use usernames.
I want to login with unique index (for better performance) with user email.
Maybe best performance will be unique index for email and password together.
Problem is that I want to be email indexed as unique for faster login.
But in this case bad user can prevent another user to register knowing his email.
The only idea I could think of some sort of unique email and password hash in one unique column. But I want know how its done the best.
Part of my user table index structure (DB is MySQL)
user_id - PRIMARY
email - UNIQUE
password
verified (after verify email)
Simple solution:
Send verification email with link to cancel registration (I didnt register)

If I have a users table but want e-mails to be usernames, should I simply have email/password as columns?

Or should I have username, email, password and set save username also as email?
edit: I am not using email as the pk but am using a unique index on the email
I feel like if I decided to change to openid/usernames I can still do that in the future by adding another column
I'd do email/password. And if you ever want to add usernames you can upgrade it then. No need to use extra fields if they're the same and you don't need them.
Might as well just have the email column since it functions as both, no point in repeating data in your table. Just remember DO NOT SAVE PASSWORDS AS CLEARTEXT :) Also you should have a Primary Key id column

How to handle optional fields in MySQL?

I have a MySQL table that records classified listings. We don't force users to join to post a listing, and therefore the listing will not always have a user_id associated with it.
I therefore need a method of recording the poster's email if they are not signed in.
Is it bad practice to create a column email that will sometimes be blank and sometimes be filled?
Or is there a better way to go about this that I don't realize?
Is it bad practice to create a column
email that will sometimes be blank and
sometimes be filled?
It is not a bad practice, no : juste use a NULL column -- that's why they exist ;-)
See 12.1.17. CREATE TABLE Syntax : in the column_definition part of the create table query, you can specify NULL or NOT NULL.
BTW: Using NULL, which literally means "no value" is better than using some kind of "impossible value", like an empty string : NULL really means "no value", and make your point obvious -- while an empty string could mean an error in your code.
And I don't really see another "logical" way, actually...
Note, though, that you'll have to handle a NULL value for the email, in your application's code, of course ;-)
this is exactly what NULL is for. but you already knew that because your user_id column will also sometimes be NULL, right?
I think the approach you have laid out is perfectly acceptable. As longneck points out, thats what NULL is for in SQL databases.
However, if you're truly concerned about it, you could save space (possibly a significant amount, depending on the column type and number of rows) if you use the user_id column for the userid and the email address, and then have another boolean column, say is_email to distinguish which type of value is stored in the user_id column. This may simplify things for you because it is likely that your application does not care, in many places, whether the data is actually a user_id or an email address.
I have a MySQL table that records classified listings. We don't force users to join to post a listing, and therefore the listing will not always have a user_id associated with it.
I therefore need a method of recording the poster's email if they are not signed in.
What is the business key of your user entity? Or, more directly: what is your user entity? Is every distinct email address a key for a User entity with some users having registered and their email set in some profile, and others not registered and giving an email address every time they post? Or do you have two distinct entities, RegisteredUser and UnknownPosterWithEmailAddress, with their attributes stored in separate places?
In the latter case, you would use a NULLable user_id and a NULLable email field, like you suggested, but then queries like "for a given post, find the email address the reply should be sent to" are going to be awkward, e.g. a list of all post with their respective reply addresses will look like this:
select post.id,
case when post.user_id is not null then user.email
else post.email end as email
from post
left join user on user.id=post.user_id;
This can get real messy after a while.
I'd rather use the former approach: each row in User is a dsitinct poster, with an non-NULLable unique email address, and a surrogate key as foreign key in posts:
create table user(id integer primary key,
email text not null unique,
is_registered boolean default false);
create table post(id integer primary key,
user_id integer not null references user(id),
content text);
If a non-registered user enters an email address, you look it up in the user table, and retrieve the user.id, adding a new entry in user if necessary. As a result, you can answer questions like: for a given email address, how many posts has this user made in the past week? via the foreign key field, without having to compare strings in some NULLable attribute field.
When a user chooses to register, you can add the registration data either in user itself or in some separate table (again with user.id as a foreign key, some might argue that a boolean field is_registered is actually redundant then). Added benefits:
If he has posted before under the same email address, now all of his old posts become associated with his new registered identity automatically.
If the user changes his email address in his profile, all replies to older posts of his "see" the new updated email address.