Friday, March 30, 2012

Devise gem for Authentication in Rails 3

Devise Authentication in Rails 3

 Devise gem features:
  • Database Authenticatable: encrypts and stores a password in the database to validate the authenticity of an user while signing in. The authentication can be done both through POST requests or HTTP Basic Authentication.
  • Token Authenticatable: signs in a user based on an authentication token (also known as “single access token”). The token can be given both through query string or HTTP Basic Authentication.
  • Confirmable: sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in.
  • Recoverable: resets the user password and sends reset instructions.
  • Registerable: handles signing up users through a registration process, also allowing them to edit and destroy their account.
  • Rememberable: manages generating and clearing a token for remembering the user from a saved cookie.
  • Trackable: tracks sign in count, timestamps and IP address.
  • Timeoutable: expires sessions that have no activity in a specified period of time.
  • Validatable: provides validations of email and password. It’s optional and can be customized, so you’re able to define your own validations.
  • Lockable: locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
  • Encryptable: adds support of other authentication mechanisms besides the built-in Bcrypt (the default).
 Steps to add devise Gem to your Application:

   1. First, add “devise” to your rails Gemfile
         gem 'devise', '1.1.rc0'

   2. Next run the bundle install command
         >$ bundle install

   Running bundle install will set you up with:
     Installing bcrypt-ruby (2.1.3) with native extensions
     Installing warden (1.0.3)
     Installing devise (1.1.5)
Following the install docs on the Devise project page..
     >$rails generate devise:install 
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml

===============================================================================

Some setup you must do manually if you haven't yet:

  1. Setup default url options for your specific environment. Here is an
     example of development environment:

       config.action_mailer.default_url_options = { :host => 'localhost:3000' }

     This is a required Rails configuration. In production it must be the
     actual host of your application

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root :to => "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

===============================================================================
Alright, based on the install output it looks like we need to do a little setup work… However, I will leave that to the reader since they may be using a pre-existing rails application…
After you are finished configuring the application its time to create your user model.
     >$rails generate devise User 
      invoke  active_record
      create    app/models/user.rb
      invoke    test_unit
      create      test/unit/user_test.rb
      create      test/fixtures/users.yml
      create    db/migrate/20110108192129_devise_create_users.rb
      inject    app/models/user.rb
       route  devise_for :users
Great, lets take a look at what the generator created starting with the migration.
class DeviseCreateUsers < ActiveRecord::Migration 
    def self.up 
      create_table(:users) do |t| 
      t.database_authenticatable :null => false
      t.recoverable
      t.rememberable
      t.trackable

      # t.confirmable
      # t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
      # t.token_authenticatable

      t.timestamps
    end

    add_index :users, :email,                :unique => true
    add_index :users, :reset_password_token, :unique => true
    # add_index :users, :confirmation_token, :unique => true
    # add_index :users, :unlock_token,       :unique => true
  end

  def self.down
    drop_table :users
  end
end
Alright, now that we understand what they mean here is what my final migration looks like:
class DeviseCreateUsers < ActiveRecord::Migration 
    def self.up 
      create_table(:users) do |t| 
      t.database_authenticatable :null => false
      t.recoverable
      t.rememberable
      t.trackable

      t.confirmable
      t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
      t.token_authenticatable

      t.timestamps
    end

    add_index :users, :email,                :unique => true
    add_index :users, :reset_password_token, :unique => true
    add_index :users, :confirmation_token,   :unique => true
    add_index :users, :unlock_token,         :unique => true
  end

  def self.down
    drop_table :users
  end
end
Now let’s take a look at our User model.
class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :token_authenticatable, :confirmable, :lockable and :timeoutable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me
end
It looks like based on our migration options that we will also have to uncomment token_authenticatable, :confirmable, :lockable and :timeoutable and add it to the devise option.
class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :token_authenticatable, :confirmable, :lockable, :timeoutable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me
end
We don’t need to setup our routes for user because devise has already added devise_for :users to our config/routes.rb for us.

Finally it’s time to migrate our database and create our user model.
     >$rake db:migrate
==  DeviseCreateUsers: migrating ==============================================
-- create_table(:users)
NOTICE:  CREATE TABLE will create implicit sequence "users_id_seq" 
         for serial column "users.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "users_pkey" 
         for table "users"
   -> 0.0553s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0020s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0021s
-- add_index(:users, :confirmation_token, {:unique=>true})
   -> 0.0115s
-- add_index(:users, :unlock_token, {:unique=>true})
   -> 0.0028s
==  DeviseCreateUsers: migrated (0.0740s) =====================================
Now it’s time to start our rails server and see what devise has given us. Run rails server from the command line and lets travel to “localhost:3000/users/sign_up” and see whats going on.
Trackr

Conclusion

Devise is easy to setup and install using Rails 3. It give me the flexibility and features I need to fulfill the authentication requirements of my application. Good documentation and setup instructions go a long way. We will see with time if I regret my decision. If anyone out there in the internets know of any helpful information that would be beneficial to this blog post please comment below!

Update

To update your Devise views run this from the command line:
   >$rails generate devise:views
This will pull the views from the gem and allow you to modify them.

1 comment: