If you want to increase your signups, ditching the password is the best way.
Before starting with this setup, make sure that transactional emails are ready and set, follow the LightningRails guide here. With Postmark set up, you will get 100 free emails per month.
Config
If it hasn't been done yet, make sure that the environment is set to the correct email delivery method:
To send Magic links, generate an instance of a magic Link with a unique token, think of it as an invitation instance:
rails g model email_link token expires_at:datetime user:references
Migrate:
rails db:migrate
In your model file email_link.rb
class EmailLink < ApplicationRecord
belongs_to :user
after_create :send_mail
def self.generate(email)
user = User.find_by(email: email)
if !user
user = User.create(email: email, password: Devise.friendly_token.first(8))
end
create(user: user, expires_at: Date.today + 1.day, token: generate_token)
end
def self.generate_token
Devise.friendly_token.first(16)
end
private
def send_mail
# Defined in mailer class
EmailLinkMailer.sign_in_mail(self).deliver_now
end
end
Generate Mailer
In the model we are creating a send_mail method, now we define it in our mailer method:
rails g mailer email_link
This should generate email_link_mailer.rb a few other files, in this mailer file, add this code:
class EmailLinkMailer < ApplicationMailer
def sign_in_mail(email_link)
@token = email_link.token
@user = email_link.user
mail to: @user.email, subject: "Here is your magic link! 🚀" # modify the subject to your liking
end
end
Now let's write a nice welcome email, no need to go above the board, the user just needs a link to sign up:
# app/views/email_link_mailer/sign_in_mail.html.erb
<p>Hello, <%= @user.email %>!</p>
<p>Someone requested a sign-in link for your account. Click the link below to sign in:</p>
<%= link_to "Sign in to my account", email_link_url(token: @token) %>
Cheers,
Bob, Founder
Route
We will need new routes to make this work.
post 'email_links/create', as: :magic_link
get 'email_links/validate', as: :email_link
Controller
We will also need a new controller.
rails g controller email_links
In the controller, we will add these methods. One method to create the new link, and one to validate that the link is correct, the latter will be linked directly in the email.
class EmailLinksController < ApplicationController
skip_before_action :authenticate_user!
def create
@email_link = EmailLink.generate(params[:email])
if @email_link
flash[:notice] = "Access email sent! Please, check your inbox to enter"
redirect_to root_path
else
flash[:alert] = "There was an error, please try again!"
redirect_to new_user_session_path
end
end
def validate
email_link = EmailLink.where(token: params[:token]).where("expires_at > ?", DateTime.now).first
unless email_link
flash[:alert] = "Invalid or expired token!"
redirect_to new_user_session_path
end
sign_in(email_link.user, scope: :user)
flash[:notice] = "Welcome! You signed in successfully 🚀"
redirect_to root_path
end
end
Views
The last thing we have to do is go to the new sessions path and replace the existing form with this new one:
This form will work for both Signup and Login, so no need to do the same setup in registrations. Just change all the signup links to redirect to sessions/new by default.
The reason I recommend adding the sessions new instead of registration is that the authenticated_user method redirects to sessions, so you can reuse that feature with your new magic link 🚀
Don't forget to restart your server as we modified the config files 😉