โšก
LightningRails
  • ๐Ÿ‘‹Welcome
  • Access the Repo
  • Getting Started
    • ๐Ÿš€Quickstart
    • ๐ŸŽจThemes
    • ๐Ÿ–ผ๏ธCustomize the views
    • ๐Ÿ”ฎDaisyUI Library
    • โšกLightning Landing
      • Quickstart
      • Theme and branding
      • Page structure
      • Publish your landing page
  • Features setup
    • ๐Ÿ“ธImages & media
    • ๐Ÿ”Admin Dashboard
    • Search Engine Optimization
    • ๐Ÿ“งAutomatic Emails
      • ๐ŸŸจPostmark
      • ๐Ÿ”ฒResend
    • ๐ŸšชLogin with Devise
    • ๐Ÿช„Magic Link Signup
    • ๐Ÿ’ณStripe Payment Gateway
    • Github Signup
    • Lucide icons
    • ๐Ÿค–Multi-provider AI
    • Open AI API
  • UI Components
    • ๐ŸฆธHeros
    • โ”FAQs
    • ๐Ÿƒcards
    • ๐Ÿ’ฌTestimonials
    • ๐Ÿ‘‹Call To Actions
    • ๐Ÿ”ฆFeatures
  • Deploying to production
    • โฌ†๏ธHeroku Deploy
    • ๐Ÿ›ก๏ธSecurity
      • ๐ŸŽ›๏ธRate Limiting
  • RESOURCES
    • ๐Ÿš€Vote for new features
    • Report an issue
    • ๐Ÿ†˜Get help on Slack
    • ๐ŸญDesign Resources
      • Maria Ba Illustrations
      • Assets Mockup Generator
      • Logo Generator
      • Tailwind Cheatsheet
      • HyperUI Tailwind Library
Powered by GitBook
On this page
  • Config
  • Model
  • Generate Mailer
  • Route
  • Controller
  • Views

Was this helpful?

  1. Features setup

Magic Link Signup

Who likes passwords? Easily setup magic link in your LightningRails app.

PreviousLogin with DeviseNextStripe Payment Gateway

Last updated 13 days ago

Was this helpful?

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, 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:

#ย config/environments/development.rb
config.action_mailer.delivery_method = :letter_opener
#config/environments/production.rb
config.action_mailer.delivery_method = :postmark

Model

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

In your user.rb file

class User < ApplicationRecord
  has_many :email_links, dependent: :destroy
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

Let's create the view file:

touch app/views/email_link_mailer/sign_in_mail.html.erb

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:

 # app/views/devise/sessions/new.html.erb

 <%= form_with(url: magic_link_path, method: :post) do %>
     <div class="col-span-6">
          <label class="input input-bordered flex items-center gap-2">
            <svg
              xmlns="http://www.w3.org/2000/svg"
              viewBox="0 0 16 16"
              fill="currentColor"
              class="h-4 w-4 opacity-70">
              <path
                d="M2.5 3A1.5 1.5 0 0 0 1 4.5v.793c.026.009.051.02.076.032L7.674 8.51c.206.1.446.1.652 0l6.598-3.185A.755.755 0 0 1 15 5.293V4.5A1.5 1.5 0 0 0 13.5 3h-11Z" />
              <path
                d="M15 6.954 8.978 9.86a2.25 2.25 0 0 1-1.956 0L1 6.954V11.5A1.5 1.5 0 0 0 2.5 13h11a1.5 1.5 0 0 0 1.5-1.5V6.954Z" />
            </svg>
            <%= email_field_tag :email, nil, placeholder: "mclovin@gmail.com" %>
          </label>
          <div class="col-span-6 sm:flex sm:items-center sm:gap-4 mt-6">
            <%= submit_tag "Log in", class: "btn btn-primary" %>
          </div>
      </div>
  <% end %>

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 ๐Ÿ˜‰

Happy Magic linking! ๐Ÿฆ„

๐Ÿช„
follow the LightningRails guide here.
Magic link just needs an email, no password ๐Ÿฅณ