/authlogic-activation-tutorial

Tutorial on authlogic account activation modified from matthooks version.

Primary LanguageRuby

Introduction

This tutorial is divided into a number of steps and walks through the process of implementing user activation functionality into your pre-existing Rails app using Authlogic. If you are just starting out with Authlogic, be sure to checkout the Authlogic Example Tutorial.

Just a reminder, the code, as is, may not work with the most recent versions of Authlogic!

Thanks to Clayton Lengel-Zigich for cleaning up the tutorial and making it easier to read!

Step 1

Let’s begin by adding an ‘active’ field with a default of false to the user model.

script/generate migration AddActiveToUsers active:boolean

  # new migration XXX_add_active_to_users.rb
  class AddActiveToUsers < ActiveRecord::Migration
    def self.up
      add_column :users, :active, :boolean, :default => false, :null => false
    end

    def self.down
      remove_column :users, :active
    end
  end

Step 2

Don’t forget to run the migration.

rake db:migrate

Authlogic automatically executes the following methods, if present, upon user action: active?, approved?, and confirmed?. Since we added an active column, the “active?” method will be dynamically generated by ActiveRecord so we can hook into this magical goodness. And we should make sure that we protect the active attribute from mass-assignments by calling attr_accessible.

  # added to user.rb
  attr_accessible :login, :email, :password, :password_confirmation, :openid_identifier

Step 3

Now try to log in. You should receive the error, “Your account is not active.” So far so good. Let’s make a controller to handle our activations:

script/generate controller activations create

  # new file app/controllers/activations_controller.rb
  class ActivationsController < ApplicationController
    before_filter :require_no_user

    def create
      @user = User.find_using_perishable_token(params[:activation_code], 1.week) || (raise Exception)
      raise Exception if @user.active?

      if @user.activate!
        flash[:notice] = "Your account has been activated!"
        UserSession.create(@user, false) # Log user in manually
        @user.deliver_welcome!
        redirect_to account_url
      else
        render :action => :new
      end
    end

  end

Step 4

I raise exceptions in these actions to make sure that someone who is already active cannot re-activate their account and to deal with an invalid perishable token. I’ll leave it up to you how you want to handle these errors — you should probably provide some sort of “My Token is Expired!” action that will reset the token and resend the activation email if the user does not get around to activating right away.

Going down the list, let’s define the missing actions. First:

  # added to user.rb
  def activate!
    self.active = true
    save
  end

Step 5

Next, let’s make sure our user gets an e-mail with his activation code when he signs up. How are we getting our activation code? The same way we get our password reset code — through our perishable token:

  # added to app/models/user.rb
  def deliver_activation_instructions!
    reset_perishable_token!
    Notifier.deliver_activation_instructions(self)
  end

  def deliver_welcome!
    reset_perishable_token!
    Notifier.deliver_welcome(self)
  end

  # added to app/models/notifier.rb
  def activation_instructions(user)
    subject       "Activation Instructions"
    from          "Binary Logic <noreply@binarylogic.com>"
    recipients    user.email
    sent_on       Time.now
    body          :account_activation_url => activate_url(user.perishable_token)
  end

  def welcome(user)
    subject       "Welcome to the site!"
    from          "Binary Logic <noreply@binarylogic.com>"
    recipients    user.email
    sent_on       Time.now
    body          :root_url => root_url
  end

  # added to config/routes.rb
  map.activate '/activate/:activation_code', :controller => 'activations', :action => 'create'
  
  <!-- new file app/views/notifier/activation_instructions.erb --> 
  Thank you for creating an account! Click the url below to activate your account!

  <%= @account_activation_url %>

  If the above URL does not work try copying and pasting it into your browser. If you continue to have problem, please feel free to contact us.

  <!-- new file app/views/notifier/welcome.erb -->
  Welcome to the site! Your account has been activated.

  <%= @root_url %>

  If the above URL does not work try copying and pasting it into your browser. If you continue to have problem, please feel free to contact us.
  

Note: I got a “Missing host to link to! Please provide :host parameter or set default_url_options[:host]” error when I tried this, so if you do to you will have to set the default_url_options in your environment.rb or environment config.

  <!-- config/environments/development.rb -->
  config.action_mailer.default_url_options = {:host => "binarylogic.com"}

Step 6

Now let’s modify the user create action:

  # modified app/controllers/users_controller.rb
  def create
    @user = User.new(params[:user])

    # Saving without session maintenance to skip
    # auto-login which can't happen here because
    # the User has not yet been activated
    if @user.save_without_session_maintenance
      @user.deliver_activation_instructions!
      flash[:notice] = "Your account has been created. Please check your e-mail for your account activation instructions!"
      redirect_to root_url
    else
      render :action => :new
    end
  end

The End

And that’s it! Let me know if you have any suggestions for improvement.