Wednesday 16 May 2012

Devise Authentication in Rails 3

Hi folk, I am going to demonstrate  step by step devise authentication for a sample app over rails 3.2.3 and ruby 1.9.3.

To create the application, you can cut and paste the code from the blog into your console ELSE do git clone rails_3_devise app and get real time experience with device. 


1. Creates a new Rails app named rails_3_devise on your computer. Type the below command.


$ rails new rails_3_devise --d mysql
 
Use the flag  --d mysql specify mysql as database, As we know rails having default sqlite db.
Now we move to app by typing 


$ cd rails_3_devise

2. Finally we have to push our code to github, So doing some basic cammand to initialize git and pushing code to github  .

$ git init
Initialized empty Git repository in /home/maisa/workspace/rails_3_devise/.git/
$ git add .
$ git commit -m "First commint" 


3. Once we make sure our app is working



$ rails s -p 4000 

And check from browser http://localhost:4000/

4. Set Up Authentication, First things first, add “devise” to your rails Gemfile in the root directory of your application And do 


$ bundle update
Fetching gem metadata from https://rubygems.org/.........
Using warden (1.1.1)
Using devise (2.1.0)
Using jquery-rails (2.0.2)
Using rails (3.2.3)
Using sass (3.1.18)

We will see latest devie 2.1.0 has installed

Now following the install docs on the Devise project page. And run

$ rails g 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. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

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

     In production, :host should be set to 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:

      
  <% flash.each do |name, msg| %>
    <%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
  <% end %>

   If you are deploying Rails 3.2.3 on Heroku, you may want to set:


       config.assets.initialize_on_precompile = false

     On config/application.rb forcing your application to not access the DB
     or load models when precompiling your assets.

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

Alright, based on the install output it looks like we need to do a little setup work… Make sure we are following all above instruction.
After you are finished configuring the application its time to create your user model.
$ rails generate devise User
      invoke  active_record
      create    db/migrate/20120516110556_devise_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/unit/user_test.rb
      create      test/fixtures/users.yml
      insert    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 change
    create_table(:users) do |t|
      ## Database authenticatable
      t.string :email,              :null => false, :default => ""
      t.string :encrypted_password, :null => false, :default => ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, :default => 0
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at

      ## Token authenticatable
      # t.string :authentication_token


      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
    # add_index :users, :authentication_token, :unique => true
  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, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me
  # attr_accessible :title, :body
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. If we then run rake routes from the command line we get:

$ rake routes user
              home_index GET    /home/index(.:format)          home#index
        new_user_session GET    /users/sign_in(.:format)       devise/sessions#new
            user_session POST   /users/sign_in(.:format)       devise/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)      devise/sessions#destroy
           user_password POST   /users/password(.:format)      devise/passwords#create
       new_user_password GET    /users/password/new(.:format)  devise/passwords#new
      edit_user_password GET    /users/password/edit(.:format) devise/passwords#edit
                         PUT    /users/password(.:format)      devise/passwords#update
cancel_user_registration GET    /users/cancel(.:format)        devise/registrations#cancel
       user_registration POST   /users(.:format)               devise/registrations#create
   new_user_registration GET    /users/sign_up(.:format)       devise/registrations#new
  edit_user_registration GET    /users/edit(.:format)          devise/registrations#edit
                         PUT    /users(.:format)               devise/registrations#update
                         DELETE /users(.:format)               devise/registrations#destroy
                    root        /                              home#index

Finally it’s time to migrate our database and create our user model.
$ rake db:migrate
==  DeviseCreateUsers: migrating ==============================================
-- create_table(:users)
   -> 0.0175s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0010s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0012s
==  DeviseCreateUsers: migrated (0.0202s) =====================================

5. Now let's create a Home Page and add custom message to index page


$ rails generate controller home index --no-controller-specs      create  app/controllers/home_controller.rb
       route  get "home/index"
      invoke  erb
      create    app/views/home
      create    app/views/home/index.html.erb
      invoke  test_unit
      create    test/functional/home_controller_test.rb
      invoke  helper
      create    app/helpers/home_helper.rb
      invoke    test_unit
      create      test/unit/helpers/home_helper_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/home.js.coffee
      invoke    scss
      create      app/assets/stylesheets/home.css.scss

And remove default public index page, As we expecting home/index will be our default page.

$ rm public/index.html
 

And will add root url to routes.rb file  and protect home_controller.rb by adding  

before_filter :authenticate_user!

At top of index action.

root :to => "home#index"

 

Now  we almost done. Finally we need to create  an Application Layout with few links like login, logout,sign. For that we Create a shared directory under app/views/. Then create the file app/views/shared/_navigation.html.erb and add:

 <% if user_signed_in? %>
  <li>
  <%= link_to('Logout', destroy_user_session_path, :method=>'delete') %>      
  </li>
<% else %>
  <li>
  <%= link_to('Login', new_user_session_path)  %>
  </li>
<% end %>
<% if user_signed_in? %>
  <li>
  <%= link_to('Edit account', edit_user_registration_path) %>
  </li>
<% else %>
  <li>
  <%= link_to('Sign up', new_user_registration_path)  %>
  </li>
<% end %>

Then use these partials in your app/views/layouts/application.html.erb file, like this:

<ul class="hmenu">
    <%= render 'shared/navigation' %>
  </ul>
  <% flash.each do |name, msg| %>
    <%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
  <% end %>
  <%= yield %>


Now Add stylesheet rules to the application.css.scss file:

header nav ul {
  list-style: none;
  margin: 0 0 2em;
  padding: 0;
}
header nav ul li {
  display: inline;
}
#flash_notice, #flash_alert {
  padding: 5px 8px;
  margin: 10px 0;
}
#flash_notice {
  background-color: #CFC;
  border: solid 1px #6C6;
}
#flash_alert {
  background-color: #FCC;
  border: solid 1px #C66;
}


That all coding part.  

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:4000/


That's expected. As we protected our home page. Now we need to sign_up and post sign_in. After using right credentials we will see


Thanks, Enjoy..!!!!

No comments:

Post a Comment