Ruby on Rails Authentication and Authorisation with EMail confirmation user activation.
What you will learn here:
  • How to create authentication and authorisation in Ruby on Rails.
  • Furthermore, when a user signs up he is sent an email to which he must respond to activate his account.
  • The IP address from which the user signs up is recorded. By default his creation date is also recorded.
  • Use a globally unique ID for users, not the default integers starting at 1. I did this because the verification link in the email contains the user id. A mischievous user can reconstruct the link with a user id smaller than his, if the default integers were used, to see what mischief he can practise. Also, of course, when it comes to users/show it's easy to use integers to page through the users. A GUID does not allow either of these two scenarios.

Install Ruby and Rails

To start off with, install Ruby and Rails if you don't already have them.
I'm assuming you're on Linux. If you're on Windows, why? So go to Ruby on Rails Wiki Page and follow the instructions to install Ruby. To make this generic over all distributions, I'll go with the compile and install from code instructions. Wherever you see $ sudo, if you don't know what that means, sign in as superuser root and do whatever sudo is supposed to do.
Make sure you have the necessary prerequisites. If you're on Debian or one of its children (Ubuntu, Mepis, etc.) do
$ sudo apt-get install build-essential libssl-dev libreadline5-dev zlib1g-dev
If not, download the libraries indicated above. The build-essential package is a list of what Debian needs to build from code. It consists of 23 packages like, bash, tar, etc. on my computer. You will need something like gcc to compile with. Use 
$ gcc -v
to see if you have it. On my machine version 4.3.2 is installed.
This will get you the latest stable Ruby package: 
$ wget ftp://ftp.ruby-lang.org/pub/ruby/stable-snapshot.tar.gz
Now follow the instructions on the wiki page. I'll repeat them here for completeness sake.
First, $ tar xzf stable-snapshot.tar.gz
Then $ cd ruby/
$ ./configure
$ make
$ sudo make install

Now see what was installed.
$ ruby -v
On my machine I get ruby 1.8.8dev (2009-06-19) [x86_64-linux]
If you have installed ruby 1.9.1 or above, you apparently don't need Ruby Gems, as it comes with the Ruby installation. However, if you need Ruby Gems, go to Ruby Forge and download the latest Ruby Gems. Note this is not the link or version of Ruby Gems on the Ruby on Rails Wiki page. Now do the following:
$ tar xzvf rubygems-1.x.x.tgz (mine was 1.3.4)
$ cd rubygems-1.x.x
$ sudo ruby setup.rb

The Wiki page talks of creating symbolic links in /usr/bin. On my system (Debian Lenny) everything was installed in /usr/local and executables, not links, placed in /usr/local/bin. You may want to have a look and see where everything is installed and create symbolic links as explained on the Wiki page, if needed.
Now install Rails:
$ sudo gem install rails
To see which rails was installed, do
$ rails -v
I get Rails 2.3.2

The Database and its Ruby Connector

You will need a database to follow along. Install either MySQL or PostgreSQL using your distribution package installer. Then set up your database so you can log into it and create databases, tables, populate the tables, etc. What this means is that you should create users (at least one) in your database and give him certain permissions. If you don't know how to do this, go to the website of the database you installed and follow the instructions. See that you install the package that connects your database to Ruby and the developer package as indicated on the Wiki page. The developer package is needed for the Ruby connector. I had to install the same for PostgreSQL. When all this is done install the Ruby connector.
$ sudo gem install mysql I installed postgresql here.
I needed to do nothing for the socket issue as explained on the Wiki page. Have a look at your database.yml file once it is generated. We will get there very soon.

The Application

We will need the following functionality:
  1. Create a new user
  2. Send e-mail to the new user
  3. New user uses the e-mail to activate his account or delete himself from the database
  4. New user can now log in
  5. Once logged in the new user can change his password
  6. User can log out
  7. User can request a new password be sent to him using his e-mail address
For all the above we will need the following forms:
  1. A sign up form
  2. A log in form
  3. A change password form
  4. A form to request a new password
Logging out will just be an action link.
Allow me a small digression. I come from a Java background. Rails uses a different paradigm to Java web applications. One does not directly request a view in Rails, one "requests" a method on a controller. Every method on a controller has an associated view. If the method is totally empty, the associated view will be served to your browser. Otherwise the method will be executed and, if no redirection or render directives are encountered, the method's associated view will be served to your browser. A method can redirect to another method, even on a different controller, resulting in the associated view of the method redirected to being served to your browser. A method can also render to another method with the same result. In the last case the url in the browser window won't change. Keep all this in mind. I've found it helps understanding the logic behind Rails. Let's get going.
To start your application, open a terminal window (Windows users, a command window) and migrate to where you want to build this project. Say /home/yourname/projects/ruby. Now enter
$ rails authenticate -d postgresql
If you are going to use Mysql enter mysql rather than postgresql. Things will scroll by on the term window and you will end up with a directory structure like this:
rails generated directory structure of a rails project
Now create your databases. For me it was:
$ createdb authenticate_development
$ createdb authenticate_production
$ createdb authenticate_test
Of course, if you don't use PostgreSQL or used a different project name, things will be different.
Now open authenticate/config/database.yml in a text editor. This is what my database.yml looks like. Fill in the user name and password in the relevant places. You will see provision is made to connect to the database using TCP/IP. Apparently this is a must in Windows. If you're on Windows, uncomment those lines.

Your model

Model is just what a class representing a database table is called. In Ruby there is no mapping between the class and the database table, like in Java where every column in the table is represented by a member of the class. Also, in Ruby the model class can contain methods used to do things on one row in the table - in this case a certain user. These things can be logging in this certain user, changing his password, etc. In Java these methods will be in a different class, an action class or session bean. Our model here is going to be the class User.rb which will be represented by a table called users.
You may remember that our users are not going to have the default integer ID generated by Rails. So, let's install the GUID plugin which will generate 22 char guids for our user primary keys. Download guid.zip and unzip into authenticate/vendor/plugins/guid/ Inside guid you should have an init.rb and README.TXT files and a lib directory.
Now a short detour; the GUID plugin uses the computer's mac address, obtained by calling /sbin/ifconfig, to generate the guid. On one of the commercial hosts, Dreamhost, one is not allowed to call /sbin/ifconfigand key generation fails. The fix is simple: migrate into the authenticate/vendor/plugins/guid/lib directory and open uuidtools.rb in a text editor. Near the top (line 106 for me) you will find @@mac_address = nil. Change that to @@mac_address = "12:23:23:45:78:34" or something similar in that format. You can obtain your computer's mac address by calling /sbin/ifconfig and use that. Of course, if you don't have the problem calling /sbin/ifconfig you don't have to do any of this.
Now, let's create our model:
$ cd authenticate  #All the commands are going to be issued from this directory, from now on.
$ ruby script/generate model user login:string clearance:integer name:string surname:string email:string ip_address:string salt:string hashed_password:string activated:boolean
    exists  app/models/
    exists  test/unit/
    exists  test/fixtures/
    create  app/models/user.rb
    create  test/unit/user_test.rb
    create  test/fixtures/users.yml
    create  db/migrate
    create  db/migrate/20090707125413_create_users.rb
                
Open authenticate/db/migrate/date_create_users.rb in a text editor. First of all (1) we have to tell Rake not to create the default, auto incrementing, integer ID primary key. Then (2) we have to tell it to create an ID column of data type varchar(22). Next (3) we have to tell it to set this column as the primary key. The areas to change the generated file are all marked in the code below.
class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users, :id => false do |t|   (1)
      t.string :id, :limit => 22                (2)
      t.string :login, :limit => 15
      t.integer :clearance
      t.string :name
      t.string :surname
      t.string :email
      t.string :ip_address
      t.string :salt
      t.string :hashed_password
      t.boolean :activated

      t.timestamps
    end
    execute "ALTER TABLE users ADD PRIMARY KEY (id)" (3)
  end

  def self.down
    drop_table :users
  end
end
                
Now we're going to create our table:
$ rake db:migrate
(in /home/chris/projects/ruby/authenticate)
==  CreateUsers: migrating ====================================================
-- create_table(:users, {:id=>false})
   -> 0.0048s
-- execute("ALTER TABLE users ADD PRIMARY KEY (id)")
NOTICE:  ALTER TABLE / ADD PRIMARY KEY will create implicit index "users_pkey" for table "users"
   -> 0.0283s
==  CreateUsers: migrated (0.0334s) ===========================================
                
If you are not using PostgreSQL, your output may not look exactly the same and you will need to log into your database in a different way.
Let's see what happened in the database and which tables were generated and how they look:
$ psql authenticate_development
Welcome to psql 8.3.7, the PostgreSQL interactive terminal.

authenticate_development=# \dt
 public | schema_migrations | table | chris
 public | users             | table | chris
                
We see two tables both belonging to me. We are interested in users.
authenticate_development=# \d users
 id              | character varying(22)       | not null
 login           | character varying(15)       |
 clearance       | integer                     |
 name            | character varying(255)      |
 surname         | character varying(255)      |
 email           | character varying(255)      |
 ip_address      | character varying(255)      |
 salt            | character varying(255)      |
 hashed_password | character varying(255)      |
 activated       | boolean                     |
 created_at      | timestamp without time zone |
 updated_at      | timestamp without time zone |
                
This is about what we wanted. You can now log out of your database.
We want to check that the e-mail address the user enters confirms to the format of an e-mail address. Getrfc822.rb and copy and paste that to a file with the same name in your project's lib directory. Personally, I would also like the people signing up not to use a web mail host, like hotmail, gmail, etc. Anyone can create an account like that and use it to activate his account with your site. Therefore, I created a small ruby file, consisting of one method,to weed out some of the more common web mail hosts. Openweb_mail_hosts.rb and copy and paste, or right click and save it to a file with the same name in your project's lib directory.
You remember I said the model class will do some work on itself. Below is what the code should look like. First of all we tell it to use the plugin to create globally unique indentifiers and the rfc822 class to check the format of e-mail addresses.
class User < ActiveRecord::Base
 include RFC822
 usesguid

  validates_length_of :login, :within => 5..40
  validates_length_of :password, :within => 5..40
  validates_presence_of :login, :email, :password, :password_confirmation, :name, :surname
  validates_uniqueness_of :login, :email
  validates_confirmation_of :password
  validates_format_of :email, :with => EmailAddress

  attr_protected :id, :salt

  attr_accessor :password, :password_confirmation

  def self.authenticate(login, pass)
  u=find(:first, :conditions=>["login = ?", login])
  return nil if u.nil?
  return u if User.encrypt(pass, u.salt)==u.hashed_password
  nil
 end

 def password=(pass)
  @password=pass
  self.salt = User.random_string(10) if !self.salt?
  self.hashed_password = User.encrypt(@password, self.salt)
 end

 def send_new_password
  new_pass = User.random_string(10)
  self.password = self.password_confirmation = new_pass
  self.save
  Notifications.deliver_forgot_password(self.email, self.login, new_pass)
 end

 def send_activate
  Notifications.deliver_activate(self.email, self.name, self.surname, self.id)
 end

 def activate?
  update_attribute('activated', true)
  if self.activated
    return true
  else
    return false
  end
 end

 protected

 def self.encrypt(pass, salt)
  Digest::SHA1.hexdigest(pass+salt)
 end

 def self.random_string(len)
  #generat a random password consisting of strings and digits
  chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
  newpass = ""
  1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
  return newpass
 end
end
                
You will see that this class contains methods to authenticate itself, set a password, send a new password to the user, activate itself, encrypt its password, etc.

Your controllers

chris@oberon:~/projects/ruby/authenticate$ ruby script/generate controller users new delete activate new_password forgot_password
    exists  app/controllers/
    exists  app/helpers/
    create  app/views/users
    exists  test/functional/
    create  test/unit/helpers/
    create  app/controllers/users_controller.rb
    create  test/functional/users_controller_test.rb
    create  app/helpers/users_helper.rb
    create  test/unit/helpers/users_helper_test.rb
    create  app/views/users/new.html.erb
    create  app/views/users/delete.html.erb
    create  app/views/users/activate.html.erb
    create  app/views/users/new_password.html.erb
    create  app/views/users/forgot_password.html.erb
                
As you can see, the above created a controller, users_controller.rb of the class UsersController, in theapp/controllers directory. This controller has the five methods, new, delete, activate, new_password and forgot_password which we specified when creating this controller. We also have a view for each of the five methods in app/views/users.
Let's also create a controller to handle logins.
chris@oberon:~/projects/ruby/authenticate$ ruby script/generate controller logins login logout logged_in logged_out
    exists  app/controllers/
    exists  app/helpers/
    exists  app/views/logins
    exists  test/functional/
    exists  test/unit/helpers/
    create  app/controllers/logins_controller.rb
    create  test/functional/logins_controller_test.rb
    create  app/helpers/logins_helper.rb
    create  test/unit/helpers/logins_helper_test.rb
    create  app/views/logins/login.html.erb
    create  app/views/logins/logout.html.erb
    create  app/views/logins/logged_in.html.erb
    create  app/views/logins/logged_out.html.erb
                
In this controller we are just interested in logging in and logging out. The logged_in and logged_out methods are going to be empty. We are just interested in their views for the sake of this tutorial.
You will also find a controller, application_controller.rb, with the two controllers we just created. Rails did this when we created the project. Code in application_controller.rb is accessible from any controller, and if we indicate a method is a helper_method it is also accessible from any view. We will be coming back to this shortly.
OK, so what's first? When we land on this site, we want to be able to sign up. That's to say, create a new user. So, let's go to the user controller. First of all, we set up a filter, which is not written yet, to require that a user be logged in before he can change his password. Then we "import" the web_mail_hosts.rb file which lives in authenticate/lib. Then we create the new method. This is what it looks like:
class UsersController < ApplicationController
  before_filter :login_required, :only=> [:new_password, :delete]
  require 'web_mail_hosts'

  def new
  if request.post?
   @user = User.new(params[:user])
   @user.ip_address=ip_address
   @user.clearance = 0;
   if not_wanted?(@user.email.to_s)  # user submitted an email address from a web mail host
    flash[:warning] = "Your email address appears to be web based"
    render  :action => 'new'
   elsif @user.save
    @user.send_activate
    flash[:notice] = "Signup successful. Activation e-mail has been sent"
    redirect_to  :controller => 'logins', :action => 'login'
   else
    flash[:warning] = "Please try again - problems saving your details to the database"
    render :action => 'new'
   end
  end
  end

  def delete
  end

  def activate
  end

  def new_password
  end

  def forgot_password
  end

end

                
The test for form data submission (if request.post?) is done so that if this method is called in any way but from a form, only its view will be displayed without executing any of its code.
We have called at least two methods, ip_address and clearance that are not implemented yet. We may want to call these methods, as well as some others, from more than one controller and maybe even from some views. So we will implement them in the already mentioned application_controller.rb. This is what that class looks like:
# Filters added to this controller apply to all controllers in the application.
 # Likewise, all the methods added will be available for all controllers.

 class ApplicationController < ActionController::Base
   helper :all # include all helpers, all the time

   before_filter :fetch_logged_in_user

   protect_from_forgery # See ActionController::RequestForgeryProtection for details

   protected
   def fetch_logged_in_user
    return unless session[:user_id]
    @current_user = User.find_by_id(session[:user_id])
   end

   def logged_in?
  ! @current_user.nil?
   end
   helper_method :logged_in?

   def clearance
  if logged_in?
    return @current_user.clearance
  else
    return nil
  end
   end
   helper_method :clearance

   def login_required
  return true if logged_in?
  session[:return_to] = request.request_uri
  flash[:notice]="You have to log in!"
  redirect_to :controller => 'logins', :action => 'login' and return false
   end

   def ip_address
  return request.remote_ip
   end

   # Scrub sensitive parameters from your log
   # filter_parameter_logging :password
 end
                

Your views

Or rather, your views this far. To start off with, we will need the main layout view that all other views are going to use as a template, application.html.erb. This file is in authenticate/app/view/layouts. This is what it should look like:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
 <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
 <title>Authenticate Application</title>
 <%= stylesheet_link_tag 'black' %>
 <%= javascript_include_tag :defaults %>

  </head>
  <body>
 <div id="shell">
     <div id="toplinks">
      <% if !logged_in? %>
            <%= link_to 'Sign Up', '/users/new' %>
  <% end %>
  <% if logged_in? %>
            <%= link_to 'Change Password', '/users/change_password' %>
  <% end %>
   </div>
   <div id="login_logout">
   <% if @current_user %>
    Logged in as: <%= @current_user.login %>
    <em><%= link_to "(Logout)", '/logins/logout' %></em>
   <% else %>
    <em>Not logged in.</em>
    <%= link_to 'Login', '/logins/login' %>
   <% end %>
   </div>
   <div class="clear"></div>
   <% unless flash[:notice].blank? %>
  <div id="notification"><%= flash[:notice] %></div>
   <% end %>
   <% unless flash[:warning].blank? %>
  <div id="warning"><%= flash[:warning] %></div>
   <% end %>
   <%= yield %>
    </div>
  </body>
</html>
                
You can download the stylesheet, which must be saved in authenticate/public/stylesheetshere and the navigation division background image, which must be saved in authenticate/public/imageshere.
The next file is authenticate/app/views/users/new.html.erb. It should look like this:
<% if !logged_in? %>
  <h2>Sign up</h2>
<%= error_messages_for 'user' %>
<p>Please fill in all fields</p>
<p>Your user name and password must be between 5 and 40 alphanumeric characters.</p>
<p>Please do not submit web mail addresses, like <b>hotmail, gmail</b> and others. Use your e-mail address with your ISP.</p>
<p><strong>Your email address must be valid.</strong> We will send you an email which you must use to activate your account.
    You will not be able to log in or upload announcements until your account is activated.</p>
<% form_for(:user, @user, :url => {:action=> 'new'}) do |f| %>
<fieldset>
  <legend>New User Data</legend>
  <p>
 <label for='user_login'>Username</label><br/>
 <%= f.text_field :login, :size => 40 %>
  </p>
  <p>
 <label for='user_name'>First Name</label><br/>
 <%= f.text_field :name, :size => 40 %>
  </p>
  <p>
 <label for='user_surname'>Surname or Last Name</label><br/>
 <%= f.text_field :surname, :size => 40 %>
  </p>
  <p>
 <label for='user_password'>Password</label><br/>
 <%= f.password_field :password, :size => 40 %>
  </p>
  <p>
 <label for='user_password_confirmation'>Password Confirmation</label><br/>
 <%= f.password_field :password_confirmation, :size => 40 %><br/>
  </p>
  <p>
 <label for='user_email'>Email</label><br/>
 <%= f.text_field :email,  :size => 40 %><br/>
  </p>
  <%= submit_tag 'Signup' %>
</fieldset>
<% end %>
<% else %>
   <h2>You are already logged in and therefore signed up</h2>
<% end %>
                
Now you are nearly ready to see the first fruits of your handiwork. All we have to do is make sure you will be presented with the sign-up page when requesting the url. Open authenticate/config/routes.rb and under# map.root :controller => "welcome" add the line map.root :controller => "users", :action => "new" Now you will be taken to the sign up form as soon as your application opens.
In the authenticate directory type ruby script/server into a terminal window and watch the server start up. Now fire up your browser and type http://localhost:3000/ into the address field. You should be rewarded with the following gratifying sight:
sign up page
All the code to create a new user is already in place, but the code for sending an activation e-mail still needs to be done. So, let's do it.

Your mailers

You will want to send out two kinds of e-mail messages:
  • Messages asking the user who signed up to activate.
  • Messages supplying a user who lost his password with a newly generated password
So, without further ado, let's do it:
chris@oberon:~/projects/ruby/authenticate$ ruby script/generate mailer notifications forgot_password activate
    exists  app/models/
    create  app/views/notifications
    exists  test/unit/
    create  test/fixtures/notifications
    create  app/models/notifications.rb
    create  test/unit/notifications_test.rb
    create  app/views/notifications/forgot_password.erb
    create  test/fixtures/notifications/forgot_password
    create  app/views/notifications/activate.erb
    create  test/fixtures/notifications/activate
                
As you can see, in authenticate/app/models, notifications.rb was generated and inauthenticate/app/views/notifications, forgot_password.erb and activate.erb were generated. These two views are templates of the e-mail that your mailer, notifications.rb is going to use. Note the .erbextension of these templates as opposed the .html.erb extensions of the other views.
Without going into too much detail, this is what activate.erb looks like:
<html>
  <head>
 <title>Mail from Authenticate</title>
  </head>
  <body>
 <center>
 <table style="width: 555px; margin: 10px auto; border: 1px black solid;">
   <tr><td style="background: #dfdfdf; text-align: center;"><h2 style="margin: 8px auto 8px auto;">Activate Your Authenticate Account</h2></td></tr>
   <tr>
  <td style="text-align: left; padding: 5px 10px;">
    <p>Welcome to <strong>Authenticate</strong>, <strong><%= @name %> <%= @surname %></strong></p>
    <p><strong>Authenticate</strong> received a sign-up request using <%= @email %>.  If it is indeed from you
    and you wish to activate your account, click <a href="http://localhost:3000/users/activate?id=<%= @id %>">here.</a></p>
    <p>Should you wish to be completely removed from our database, click
    <a href="http://localhost:3000/users/delete?id=<%= @id %>">here.</a></p>
  </td>
   </tr>
 </table>
 </center>
  </body>
</html>
                
You will notice that this is a simple html layout for an e-mail. Everyting is in the code, no images or style sheets to be downloaded from elsewhere. For e-mails a simple table layout is best.
And this is what forgot_password.erb looks like:
<html>
  <head>
 <title>Mail from Authenticate</title>
  </head>
  <body>
 <center>
 <table style="width: 555px; margin: 10px auto; border: 1px black solid;">
   <tr><td style="background: #dfdfdf; text-align: center;"><h2 style="margin: 8px auto 8px auto;">Your Lost Password</h2></td></tr>
   <tr>
  <td style="text-align: left; padding: 5px 10px;">
    <p><strong>Authenticate</strong> received a request for a password replacement from your e-mail address.  As your password is stored in a
    hashed format in our database, we cannot tell you what your password was.  We have generated a new, random password for you.  Please note
    that it is case sensitive.</p>
    <p>Your username is <em><%= @login %></em>. Your new password is <em><%= @pass %></em>. Please login and change it to something more memorable.</p>
    <p><a href="http://localhost:3000/logins/login">Click Here to Log In</a>
  </td>
   </tr>
 </table>
 </center>
  </body>
</html>
                
Much the same goes for forgot_password.erb as for activate.erb.
app/models/notifications.rb looks like this:
class Notifications < ActionMailer::Base

  def forgot_password(to, login, pass, sent_at = Time.now)
 @subject    = "Your lost password"
 @body['login']=login
 @body['pass']=pass
 @recipients = to
 @from = 'you@your_isp.com'
 @sent_on = sent_at
 @content_type = "text/html"
  end

  def activate(to, name, surname, id, sent_at = Time.now)
 @subject    = 'Account activation at Authenticate'
 @body['name']=name
 @body['surname']=surname
 @body['email']=to
 @body['id']=id
 @recipients = to
 @from = 'you@your_isp.com'
 @sent_on = sent_at
 @content_type = "text/html"
  end
end
                
It is clear that things like @body['login'] get tranferred to the templates, in this case to <%= @login %>.

Configuring your SMTP server

I have Exim installed on my Debian box. My ISP would not allow me to send mail using another SMTP server, but theirs. Also, all mail going out through them must have their domain and the From: field. Therefore my From address must be my email address with them. That would of course prevent me from sending 2 million spam messages apparently originating from elsewhere through their network. So I set up Exim to use a smart host SMTP server for messages going out of the local network. This smart SMTP server is of course my ISP's SMTP server. I fed its details into Exim and use Exim as if it is the SMTP server. You can try and use the SMTP server of your ISP directly. In that case type in mail.your_isp.com or whatever is the address of your ISP's SMTP server where you see localhost in the example.
Here is what the end of my authenticate/config/environment.rb file looks like:
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
  # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
  # config.i18n.default_locale = :de
  #ActionMailer settings
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
       :address   => 'localhost',
       :port   => 25,
       :domain   => 'your_isp.com'
 }
    config.action_mailer.raise_delivery_errors = true
    config.action_mailer.perform_deliveries = true
    config.action_mailer.default_charset = 'utf-8'
end
                

Finally...

Fire up your server by typing ruby script/server into your term window, open your browser and go tohttp://localhost:3000. You will see the sign up form. Fill it in and click the button. You should see the following:
signed up message
If sending the e-mail worked, you should find an e-mail looking like this in your inbox:
activation e-mail
However, before you can click any of the links we have to implement the methods in your controller handling those links. So, let's go to authenticate/apps/controllers/users_controller.rb and complete the four remaining methods. This is what they should look like:
def delete
  if request.get?
   u=User.find_by_id(session[:user_id].to_s)
   if u == nil
    flash[:warning] = "You must be logged in to delete yourself"
    redirect_to :controller => 'logins', :action => 'login'
   else
    session[:user_id] = nil #log out
    u.destroy
    flash[:notice] = "You were deleted from the database and logged out"
    redirect_to :controller => 'logins', :action => 'logged_out'
   end
  end
  end

  def activate
  if request.get?
   user=User.find_by_id(params[:id])
   puts user.name + ' ' + user.surname
   if user.activate?
    flash[:notice]="You have been activated and can now log in"
    redirect_to :controller => 'logins', :action => 'login'
   else
    flash[:warning]="We could not activate you.  Send us email."
    redirect_to :controller => 'logins', :action => 'login'
   end
  end
  end

  def new_password
  if request.post?
   @user=User.find_by_id(session[:user_id].to_s)
   if @user.update_attributes(:password=>params[:password], :password_confirmation => params[:password_confirmation])
    flash[:notice]="Password Changed"
    redirect_to :controller => 'logins', :action => 'logged_in'
   end
  end
  end

  def forgot_password
  if request.post?
   u= User.find_by_email(params[:email])
   if u
    if u.send_new_password
     flash[:notice]  = "A new password has been sent by email."
     redirect_to  :controller => 'logins',:action => 'login'
    else
     flash[:warning]  = "EMail address OK, but couldn't send password"
     render :action => 'forgot_password'
    end
   else
    flash[:warning] = "No such email address on record"
    render :action => 'forgot_password'
   end
  end
  end
                
If you now click on the link to activate you in your e-mail, you will be rewarded with the following page in your browser:
activated page

Login functionality

It is very obvious that we haven't done the login page yet. Go toauthenticate/app/views/logins/login.html.erb and complete it to look like:
<h2>Login</h2>
<% form_tag '/logins/login' do %>
  <fieldset>
 <legend>Please log in</legend>
 <p>
  <label>Username:</label><br />
  <%= text_field_tag :login %>
 </p>
 <p>
  <label>Password:</label><br />
  <%= password_field_tag :password %>
 </p>
 <p><%= submit_tag 'login' %></p>
  </fieldset>
<% end %>
<br />

   <%= link_to 'I forgot my password', :controller => 'users', :action => 'forgot_password' %><br /><br />
                
If you now refresh the page you will get the real login page:
login page
All that remains is your logins_controller.rb It should look like below:
class LoginsController < ApplicationController

  def new
  end

  def login
   @current_user = User.authenticate(params[:login], params[:password])
   if @current_user
    if @current_user.activated
     session[:user_id] = @current_user.id
     flash[:notice]  = "Login successful"
     if session[:return_to]
      redirect_to session[:return_to]
      session[:return_to] = nil
     else
      redirect_to :action => 'logged_in'
     end
    else
     flash[:warning]="Your account is not activated"
     render :action => 'login'
    end
   else
    flash[:warning] = "No such user"
    render :action => 'login'
   end
  end

  def logout
   @current_user = session[:user_id] = nil
   flash[:notice] = 'Logged out'
   redirect_to :action => 'logged_out'
  end

   def logged_in
   end

   def logged_out
   end

 end
                
If you know fill in your user name and password and click the login button you will be logged in:
logged in page
Clicking the logout link will now log you out.
The remaining methods are now just more of the same. Changing your password or deleteting yourself once logged in is covered in the code. Similarly, requesting that a new password be mailed to you is very similar to signing up. There are a few views you don't have the code for, but they are all included in thecode which you can download.
The functionality you have learned here is very useful. This is it. Write a note to let us know what you think of all this.
Use and empty line to separate paragraphs in the "Comment" text area.
Links and html markup are not allowed.

0 comments: