Skip to content
Shinichi Maeshima edited this page Jul 8, 2025 · 36 revisions

In this tutorial we will build upon the app created at Simple Password Authentication so make sure you understand it.

First add some db fields:

ActiveRecord

bin/rails g sorcery:install user_activation --only-submodules

Which will create:

class SorceryUserActivation < ActiveRecord::Migration[8.0]
  def change
    add_column :users, :activation_state, :string, default: nil
    add_column :users, :activation_token, :string, default: nil
    add_column :users, :activation_token_expires_at, :datetime, default: nil

    add_index :users, :activation_token
  end
end
bin/rails db:migrate

Mongoid

For mongoid just add these three fields to your User model :

field :activation_state,            type: String
field :activation_token,            type: String
field :activation_token_expires_at, type: DateTime

Note that the token_expires_at field is only needed if you have setup user.activation_token_expiration_period in the sorcery initializer.

In addition you can add an index on the token field :

index({ activation_token: 1 }, { unique: true, background: true })
bin/rails db:mongoid:create_indexes

Now our database is ready, we need a mailer with two actions:

bin/rails g mailer UserMailer activation_needed_email activation_success_email

You really don't have to use ActionMailer. You can use any ruby object that responds to the above actions. Actually these method names are configurable too! This is useful in case you want to send emails in the background, with gems such as 'delayed_job'. Simply pass your own 'mailer' and make it create the background jobs as you normally would, when triggered by Sorcery.

We need to edit the mailer and add a 'user' parameter to each action because sorcery will send each action the new user as a parameter:

# app/mailers/user_mailer.rb
def activation_needed_email(user)
...

def activation_success_email(user)
...

Then add the user_activation submodule:

# config/initializers/sorcery.rb
Rails.application.config.sorcery.submodules = [:user_activation, bla, bla, ...]

And configure the User model with our mailer defined:

# config/initializers/sorcery.rb
Rails.application.config.sorcery.configure do |config|
  ...
  config.user_config do |user|
    ...
    user.user_activation_mailer = UserMailer
    ...
  end
end

Add the routes accordingly:

# config/routes.rb
resources :users do
  member do
    get :activate
  end
end

Now, when a user is created, an activation email will be sent to them. When saving the user, an activation token and its expiration time will be automatically set, ensuring the email contains a valid token.

@user = User.new(user_params)
if @user.save
  # activation token will be set, and activation email will be sent automatically
end

Currently, it's not a very informative email, but we will fix that:

# app/mailers/user_mailer.rb
def activation_needed_email(user)
  @user = user
  @url  = activate_user_url(@user.activation_token)
  mail(to: user.email, subject: 'Welcome to My Awesome Site')
end

def activation_success_email(user)
  @user = user
  @url  = login_url
  mail(to: user.email, subject: 'Your account is now activated')
end
# app/views/user_mailer/activation_needed_email.text.erb
Welcome to example.com, <%= @user.email %>
===============================================

You have successfully signed up to example.com,
your username is: <%= @user.email %>.

To login to the site, just follow this link: <%= @url %> .

Thanks for joining and have a great day!

Here is the equivalent in html:

# app/views/user_mailer/activation_needed_email.html.erb
<!DOCTYPE html>
<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
  </head>
  <body>
    <h1> Welcome <%= @user.email %> </h1>
    <p>
      You have successfully signed up to www.example.com, and your username is: <%= @user.email %>.
    </p>
    To login to the site, just follow this link: <%= @url %> .
    <p>
    </p>
    <p>Thanks for joining and have a great day!</p>
  </body>
</html>
# app/views/user_mailer/activation_success_email.text.erb
Congratulations, <%= @user.email %>!

You have successfully activated your example.com account,
your username is: <%= @user.email %>.

To login to the site, just follow this link: <%= @url %>.

Thanks for joining and have a great day!

Nice. The user will receive an activation URL that won't work because we haven't added the necessary code for it. Let's add a controller action that will activate users:

# app/controllers/users_controller.rb
skip_before_action :require_login, :only => [:index, :new, :create, :activate]

def activate
  if @user = User.load_from_activation_token(params[:id])
    @user.activate!
    redirect_to login_path, notice: 'User was successfully activated.', status: :see_other
  else
    not_authenticated
  end
end

@user.activate! will make the user active, send a success email and clear the activation code.

If you don't want a success email, in the sorcery configuration of the model, set activation_success_email_method_name to nil.

You can set various other options for this submodule. Please take a look at the documentation for details.

To resend the activation email after user changes email address, add following callbacks to the user model:

# app/models/user.rb
before_update :setup_activation, if: -> { email_changed? }
after_update_commit :send_activation_needed_email!, if: -> { previous_changes["email"].present? }

setup_activation is needed here to generate a new activation token when the user's email changes.

Clone this wiki locally