Email verification with Rails 8 auth: Part 1
Summary
Discover one way of doing email verification, building on top of what the Rails 8 auth gives youLesson
Rails 8 comes with an authentication generator, that might let you consider not using a gem like Devise or similar. However, Devise would give you additional features like email verification, so this burden would fall to you to implement. This lesson gets you started on how you might achieve this. Just be aware, this is just one way of doing things, use your brain to judge if this makes sense in your case.
How to verify an Email address?
This is often done by sending an Email with a special Link to the User, if he clicks it, you can assume that the User has access to this Inbox. This is mostly to protect other people from receiving mail in case the User on the site is giving a stranger's address, it could of course also be a "throw-away" email address, like some services on the web provide.
Also note, an alternative to consider is to present the user with an input during signup, where the user must enter a code he received via Email, this has the advantage of keeping the user in the same tab, with the huge disadvantage of blocking him potentially at an important step while using the Webapp. We're sticking with the special link for now.
Implementation
Let's kick it off with an new model that takes on the responsibility of tracking whether an Email has been verified by the user or not. You can run the following generator:
bin/rails g model EmailChange user:references from to confirmed_at:datetime
Why EmailChange
? There is a sibling use-case to initial Email verification that is to verify an address again when the User wants to change it by himself later on. One can consider the initial check to be a special case where the Email changes from nil
to the initial value.
In addition, in order to not always query the database for EmailChange
records in case we want to know if a User did at some point verify his Email, I think it is a reasonable decision to also add a boolean field to the User model to indicate this. Is this a violation of keeping the code DRY
? I'd argue no, since there are different responsibilities for both, one models the change over time, while the other symbolized that User is safe to be receiving Emails. Use the following migration:
bin/rails g migration AddEmailVerifiedToUsers email_verified:boolean
I would recommend to change the resulting migration to set the default for the field to false
, see below
class AddEmailVerifiedToUsers < ActiveRecord::Migration[8.0]
def change
add_column :users, :email_verified, :boolean, default: false
end
end
In the next part, we will continue with writing the code to send out the link and a controller to consume it after the User clicks on it.