Sarav's Weblog

Technical Articles for RoR Developers

Tag Archives: gem authlogic

Rails 3 – AuthLogic implementation – A basic tutorial

Last week I had a chance to implement authlogic for one of my projects. Initially I planned to go with Devise – Flexible authentication solution for Rails. It can be easily to plug and play. But I had a different intent/requirement to go with authlogic.

This tutorial will explain about, AutuhLogic implementation with rails 3. I’m just going to go over the basic commands/files that you need to get the framework up and working. Please refer to this link “https://github.com/binarylogic/authlogic” for a depth information. Reading required ūüôā I believe you have already installed rails 3 and other required gems. Here we go..

Auth Logic Basic Set up – Installation and configuration
Install authlogic gem

$ [sudo] gem install authlogic

create new application

$rails new auth_logic_implementation

Include the gem in the gem file #Gemfile

gem “authlogic”

database connectivity
I’ve used “mysql” for database connectivity. Change the database settings based on your mysql settings.

development:
adapter: mysql
database: auth_logic_development
host: 127.0.0.1
username: root
password: root

create database – run the following command

$rake db:create

Working with Models
create user and user_session models.

$rails g model user_session
$rails g model user

User session models will take care of the user sessions. In order to achieve this you have to inherit user_session model from AuthLogic.(ie AuthLogic instead of ActiveRecord)”

class UserSession < Authlogic::Session::Base
end

Then, in the user model, you have to tell Authlogic that its the model that you wand to use for logging in and out.

class User < ActiveRecord::Base
  acts_as_authentic do |c|
  end # block optional
end

and then update the migration files

 class CreateUserSessions < ActiveRecord::Migration
 def change
    create_table :user_sessions do |t|
      t.string :session_id, :null => false
      t.text :data
      t.timestamps
    end

    add_index :user_sessions, :session_id
    add_index :user_sessions, :updated_at

  end
end

#

class CreateUsers <ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string    :name,                :null => false, :default => ''
      t.string    :login,             :null => false
      t.string    :crypted_password,    :null => false
      t.string    :password_salt,       :null => false
      t.string    :email,               :null => false
      t.string    :persistence_token,   :null => false
      t.string    :single_access_token, :null => false
      t.string    :perishable_token,    :null => false                   

      t.integer   :login_count,         :null => false, :default => 0
      t.integer   :failed_login_count,  :null => false, :default => 0
      t.datetime  :last_request_at
      t.datetime  :current_login_at
      t.datetime  :last_login_at
      t.string    :current_login_ip
      t.string    :last_login_ip                                           

      t.timestamps
    end
  end
end

Make sure you have a model that you will be authenticating with. Since we are using the User model it should look something like:

class User < ActiveRecord::Base

  acts_as_authentic do |c|
    c.login_field = 'email'

  end # block optional

end

Do the migration

$rake db:migrate

Application controller and helper methods

class ApplicationController < ActionController::Base
  protect_from_forgery 

  #filter_parameter_logging :password, :password_confirmation # there are underscores :-|

  helper_method :current_user_session, :current_user

  private
    def current_user_session
      return @current_user_session if defined?(@current_user_session)
      @current_user_session = UserSession.find
    end

    def current_user
      return @current_user if defined?(@current_user)
      @current_user = current_user_session && current_user_session.user
    end

    def require_user
      logger.debug "ApplicationController::require_user"
      unless current_user
        store_location
        flash[:notice] = "You must be logged in to access this page"
        redirect_to new_user_session_url
        return false
      end
    end

    def require_no_user
      logger.debug "ApplicationController::require_no_user"
      if current_user
        store_location
        flash[:notice] = "You must be logged out to access this page"
       # redirect_to home_index_path
        return false
      end
    end

    def store_location
      #session[:return_to] = request.request_uri
    end

    def redirect_back_or_default(default)
      redirect_to(session[:return_to] || default)
      session[:return_to] = nil
    end

end

user_sessions controller, view, and routes

Controller

$ rails g controller user_sessions

class UserSessionsController  [:new, :create]
  before_filter :require_user, :only => :destroy

  def new
    @user_session = UserSession.new
  end

  def create
    @user_session = UserSession.new(params[:user_session])
    if @user_session.save
      flash[:notice] = "Login successful!"
      redirect_back_or_default account_url(@current_user)
    else
      render :action => :new
    end
  end

  def destroy
    current_user_session.destroy
    flash[:notice] = "Logout successful!"
    redirect_back_or_default new_user_session_url
  end
end

Views

<h1>Login</h1>
# app/views/user_sessions/new.html.erb
<%= form_for @user_session, :as => :user_session, :url => { :action => "create" } do |f| %>
   <%= render "shared/error_messages", :target => @user_session %>
  <%= f.label :email %><br />
  <%= f.text_field :email %><br />
  <br />
  <%= f.label :password %><br />
  <%= f.password_field :password %><br />
  <br />
  <%= f.check_box :remember_me %><%= f.label :remember_me %><br />
  <br />
  <%= f.submit "Login" %>
<% end %>

Users and User Registration

$ rails g controller users

class UsersController < ApplicationController    before_filter :require_user, :only => [:show, :edit, :update]

  def new
    @user = User.new
  end

  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
      flash[:notice] = "Your account has been created."
      redirect_to signup_url
    else
      flash[:notice] = "There was a problem creating you."
      render :action => :new
    end

  end

  def show
    @user = current_user
  end

  def edit
    @user = current_user
  end

  def update
    @user = current_user # makes our views "cleaner" and more consistent
    if @user.update_attributes(params[:user])
      flash[:notice] = "Account updated!"
      redirect_to account_url
    else
      render :action => :edit
    end
  end

end

Views

#app/views/users/_form.html.erb

<%= render "shared/error_messages", :target => @user %>

<p>
<%= form.label :name %><br />
<%= form.text_field :name %>
</p>
<p>
<%= form.label :email %><br />
<%= form.text_field :email %>
</p>
<p>
<%= form.label :password, form.object.new_record? ? nil : "Change password" %><br />
<%= form.password_field :password %>
</p>
<p>
<%= form.label :password_confirmation %><br />
<%= form.password_field :password_confirmation %>
</p>

#app/views/users/new.html.erb
<h1>Register</h1>

<%= form_for @user do |f| %>
<%= render :partial => "form", :object => f, :locals => { :user => @user } %>
<%= f.submit "Register" %>
<% end %>

# app/views/users/show.html.erb
<p>
<b>Email:</b>
<%=h @user.email %>
</p>

<p>
<b>Login count:</b>
<%=h @user.login_count %>
</p>

<p>
<b>Last request at:</b>
<%=h @user.last_request_at %>
</p>

<p>
<b>Last login at:</b>
<%=h @user.last_login_at %>
</p>

<p>
<b>Current login at:</b>
<%=h @user.current_login_at %>
</p>

<p>
<b>Last login ip:</b>
<%=h @user.last_login_ip %>
</p>

<p>
<b>Current login ip:</b>
<%=h @user.current_login_ip %>
</p>

<%= link_to 'Edit Account', edit_account_path %>

#app/views/shared/_error_messages.html.erb
<% if target.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(target.errors.count, "error") %> prohibited this record from being saved:</h2>
<ul>
<% target.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

Routes

#config/routes.rb
  resources :user_sessions

  match 'login' => "user_sessions#new",      :as => :login
  match 'logout' => "user_sessions#destroy", :as => :logout

  resources :users  # give us our some normal resource routes for users
  resource :user, :as => 'account'  # a convenience route

  match 'signup' => 'users#new', :as => :signup

  root :to => 'users#new'

$rake routes

    user_sessions GET    /user_sessions(.:format)          {:controller=>"user_sessions", :action=>"index"}
                  POST   /user_sessions(.:format)          {:controller=>"user_sessions", :action=>"create"}
 new_user_session GET    /user_sessions/new(.:format)      {:controller=>"user_sessions", :action=>"new"}
edit_user_session GET    /user_sessions/:id/edit(.:format) {:controller=>"user_sessions", :action=>"edit"}
     user_session GET    /user_sessions/:id(.:format)      {:controller=>"user_sessions", :action=>"show"}
                  PUT    /user_sessions/:id(.:format)      {:controller=>"user_sessions", :action=>"update"}
                  DELETE /user_sessions/:id(.:format)      {:controller=>"user_sessions", :action=>"destroy"}
            login        /login(.:format)                  {:controller=>"user_sessions", :action=>"new"}
           logout        /logout(.:format)                 {:controller=>"user_sessions", :action=>"destroy"}
            users GET    /users(.:format)                  {:controller=>"users", :action=>"index"}
                  POST   /users(.:format)                  {:controller=>"users", :action=>"create"}
         new_user GET    /users/new(.:format)              {:controller=>"users", :action=>"new"}
        edit_user GET    /users/:id/edit(.:format)         {:controller=>"users", :action=>"edit"}
             user GET    /users/:id(.:format)              {:controller=>"users", :action=>"show"}
                  PUT    /users/:id(.:format)              {:controller=>"users", :action=>"update"}
                  DELETE /users/:id(.:format)              {:controller=>"users", :action=>"destroy"}
          account POST   /user(.:format)                   {:controller=>"users", :action=>"create"}
      new_account GET    /user/new(.:format)               {:controller=>"users", :action=>"new"}
     edit_account GET    /user/edit(.:format)              {:controller=>"users", :action=>"edit"}
                  GET    /user(.:format)                   {:controller=>"users", :action=>"show"}
                  PUT    /user(.:format)                   {:controller=>"users", :action=>"update"}
                  DELETE /user(.:format)                   {:controller=>"users", :action=>"destroy"}
           signup        /signup(.:format)                 {:controller=>"users", :action=>"new"}
             root        /                                 {:controller=>"users", :action=>"new"}

Start the application

$ rails server

Visit http://localhost:3000 – default root path set to signup. Otherwise you can hit /signup to register an account! Then log out by going to /logout, and try logging back in at /login.

Note: Dont forget to delete the public/index.html

References
The majority of the content was taken from the Authlogic tutorial on github.
and thanks to http://joelgreutman.com/2011/03/13/rails-3-and-authlogic-basic-setup

Advertisements