Authenticating Your Application with Devise

Exclusive offer: get 50% off this eBook here
Learning Devise for Rails

Learning Devise for Rails — Save 50%

Use Devise to make your Rails application accessible, user friendly, and secure with this book and ebook

£11.99    £6.00
by Giovanni Sakti Hafiz Badrie Lubis Nia Mutiara | October 2013 | Open Source

A "state of the art" application sometimes requires more customizations from Devise, such as customization for signing in, updating accounts, or resetting a user's password. When you first install Devise with its default settings, you will not get these features. That's why you will need to dig deeper to have a more comprehensive understanding about Devise, and this article by Hafiz, Nia Mutiara, and Giovanni Sakti, authors of Learning Devise for Rails, will help you do just that.

(For more resources related to this topic, see here.)

Signing in using authentication other than e-mails

By default, Devise only allows e-mails to be used for authentication. For some people, this condition will lead to the question, "What if I want to use some other field besides e-mail? Does Devise allow that?" The answer is yes; Devise allows other attributes to be used to perform the sign-in process.

For example, I will use username as a replacement for e-mail, and you can change it later with whatever you like, including userlogin, adminlogin, and so on. We are going to start by modifying our user model. Create a migration file by executing the following command inside your project folder:

$ rails generate migration add_username_to_users username:string

This command will produce a file, which is depicted by the following screenshot:

The generated migration file

Execute the migrate (rake db:migrate) command to alter your users table, and it will add a new column named username. You need to open the Devise's main configuration file at config/initializers/devise.rb and modify the code:

config.authentication_keys = [:username] config.case_insensitive_keys = [:username] config.strip_whitespace_keys = [:username]

You have done enough modification to your Devise configuration, and now you have to modify the Devise views to add a username field to your sign-in and sign-up pages. By default, Devise loads its views from its gemset code. The only way to modify the Devise views is to generate copies of its views. This action will automatically override its default views. To do this, you can execute the following command:

$ rails generate devise:views

It will generate some files, which are shown in the following screenshot:

Devise views files

As I have previously mentioned, these files can be used to customize another view. But we are going to talk about it a little later in this article. Now, you have the views and you can modify some files to insert the username field. These files are listed as follows:

  • app/views/devise/sessions/new.html.erb: This is a view file for the sign-up page. Basically, all you need to do is change the email field into the username field.

    #app/views/devise/sessions/new.html.erb <h2>Sign in</h2> <%= notice %> <%= alert %> <%= form_for(resource, :as => resource_name, :url => session_path (resource_name)) do |f| %> <div><%= f.label :username %><br /> <%= f.text_field :username, :autofocus => true %><div> <div><%= f.label :password %><br /> <%= f.password_field :password %></div> <% if devise_mapping.rememberable? -%> <div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div> <% end -%> <div><%= f.submit "Sign in" %></div> <% end %> %= render "devise/shared/links" %>

    You are now allowed to sign in with your username. The modification will be shown, as depicted in the following screenshot:

    The sign-in page with username

  • app/views/devise/registrations/new.html.erb: This file is a view file for the registration page. It is a bit different from the sign-up page; in this file, you need to add the username field, so that the user can fill in their username when they perform the registration.

    #app/views/devise/registrations/new.html.erb <h2>Sign Up</h2> <%= form_for() do |f| %> <%= devise_error_messages! %> <div><%= f.label :email %><br /> <%= f.email_field :email, :autofocus => true %></div> <div><%= f.label :username %><br /> <%= f.text_field :username %></div> <div><%= f.label :password %><br /> <%= f.password_field :password %></div> <div><%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation %></div> <div><%= f.submit "Sign up" %></div> <% end %> <%= render "devise/shared/links" %>

    Especially for registration, you need to perform extra modifications. Mass assignment rules written in the app/controller/application_controller.rb file, and now, we are going to modify them a little. Add username to the sanitizer for sign-in and sign-up, and you will have something as follows:

    #these codes are written inside configure_permitted_parameters function devise_parameter_sanitizer.for(:sign_in) {|u| u.permit(:email, :username )} devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:email, :username, :password, :password_confirmation)}

    These changes will allow you to perform a sign-up along with the username data. The result of the preceding example is shown in the following screenshot:

    The sign-up page with username

I want to add a new case for your sign-in, which is only one field for username and e-mail. This means that you can sign in either with your e-mail ID or username like in Twitter's sign-in form. Based on what we have done before, you already have username and email columns; now, open /app/models/user.rb and add the following line:

attr_accessor :signin

Next, you need to change the authentication keys for Devise. Open /config/initializers/devise.rb and change the value for config.authentication_keys, as shown in the following code snippet:

config.authentication_keys = [ :signin ]

Let's go back to our user model. You have to override the lookup function that Devise uses when performing a sign-in. To do this, add the following method inside your model class:

def self.find_first_by_auth_conditions(warden_conditions) conditions = warden_conditions.dup where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => signin.downcase }]).first end

As an addition, you can add a validation for your username, so it will be case insensitive. Add the following validation code into your user model:

validates :username, :uniqueness => {:case_sensitive => false}

Please open /app/controller/application_controller.rb and make sure you have this code to perform parameter filtering:

before_filter :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.for(:sign_in) {|u| u.permit(:signin)} devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:email, : username, :password, :password_confirmation)} end

We're almost there! Currently, I assume that you've already stored an account that contains the e-mail ID and username. So, you just need to make a simple change in your sign-in view file (/app/views/devise/sessions/new.html.erb). Make sure that the file contains this code:

<h2>Sign in</h2> <%= notice %> <%= alert %> <%= form_for(resource, :as => resource_name, :url => session_path (resource_name)) do |f| %> <div><%= f.label "Username or Email" %><br /> <%= f.text_field :signin, :autofocus => true %></div> <div><%= f.label :password %><br /> <%= f.password_field :password %></div> <% if devise_mapping.rememberable? -%> <div><%= f.check_box :remember_me %> <%= f.label :remember_me %> </div> <% end -%> <div><%= f.submit "Sign in" %></div> <% end %> <%= render "devise/shared/links" %>

You can see that you don't have a username or email field anymore. The field is now replaced by a single field named :signin that will accept either the e-mail ID or the username. It's efficient, isn't it?

Updating the user account

Basically, you are already allowed to access your user account when you activate the registerable module in the model. To access the page, you need to log in first and then go to /users/edit. The page is as shown in the following screenshot:

The edit account page

But, what if you want to edit your username or e-mail ID? How will you do that? What if you have extra information in your users table, such as addresses, birth dates, bios, and passwords as well? How will you edit these? Let me show you how to edit your user data including your password, or edit your user data without editing your password.

  • Editing your data, including the password: To perform this action, the first thing that you need to do is modify your view. Your view should contain the following code:

    <div><%= f.label :username %><br /> <%= f.text_field :username %></div>

    Now, we are going to overwrite Devise's logic. To do this, you have to create a new controller named registrations_controller. Please use the rails command to generate the controller, as shown:

    $ rails generate controller registrations update

    It will produce a file located at app/controllers/. Open the file and make sure you write this code within the controller class:

    class RegistrationsController < Devise::RegistrationsController def update new_params = params.require(:user).permit(:email,:username, : current_password, :password,:password_confirmation) @user = User.find(current_user.id) if @user.update_with_password(new_params) set_flash_message :notice, :updated sign_in @user, :bypass => true redirect_to after_update_path_for(@user) else render "edit" end end end

    Let's look at the code. Currently, Rails 4 has a new method in organizing whitelist attributes. Therefore, before performing mass assignment attributes, you have to prepare your data. This is done in the first line of the update method.

    Now, if you see the code, there's a method defined by Devise named update_with_password. This method will use mass assignment attributes with the provided data. Since we have prepared it before we used it, it will be fine.

    Next, you have to edit your route file a bit. You should modify the rule defined by Devise, so instead of using the original controller, Devise will use the controller you created before. The modification should look as follows:

    devise_for :users, :controllers => {:registrations => "registrations"}

    Now you have modified the original user edit page, and it will be a little different. You can turn on your Rails server and see it in action. The view is as depicted in the following screenshot:

    The modified account edit page

    Now, try filling up these fields one by one. If you are filling them with different values, you will be updating all the data (e-mail, username, and password), and this sounds dangerous. You can modify the controller to have better data update security, and it all depends on your application's workflows and rules.

  • Editing your data, excluding the password: Actually, you already have what it takes to update data without changing your password. All you need to do is modify your registrations_controller.rb file. Your update function should be as follows:

    class RegistrationsController < Devise::RegistrationsController def update new_params = params.require(:user).permit(:email,:username, : current_password, :password,:password_confirmation) change_password = true if params[:user][:password].blank? params[:user].delete("password") params[:user].delete("password_confirmation") new_params = params.require(:user).permit(:email,:username) change_password = false end @user = User.find(current_user.id) is_valid = false if change_password is_valid = @user.update_with_password(new_params) else @user.update_without_password(new_params) end if is_valid set_flash_message :notice, :updated sign_in @user, :bypass => true redirect_to after_update_path_for(@user) else render "edit" end end end

The main difference from the previous code is now you have an algorithm that will check whether the user intends to update your data with their password or not. If not, the code will call the update_without_password method. Now, you have codes that allow you to edit with/without a password. Now, refresh your browser and try editing with or without a password. It won't be a problem anymore.

Summary

Now, I believe that you will be able to make your own Rails application with Devise. You should be able to make your own customizations based on your needs.

Resources for Article:


Further resources on this subject:


Learning Devise for Rails Use Devise to make your Rails application accessible, user friendly, and secure with this book and ebook
Published: October 2013
eBook Price: £11.99
Book Price: £18.99
See more
Select your format and quantity:

About the Author :


Giovanni Sakti

Giovanni Sakti has been a developer for 10 years with an emphasis on developing web applications in Java and Ruby. His latest projects and research are focused on API-based web applications with AngularJS as the client-side framework.

He is an active member of the Indonesian Ruby (id-ruby) community and sometimes gives talks about Ruby-related topics there. He writes regularly on his blog —http://mightygio.com— primarily about Ruby, Rails, AngularJS, and other programming topics.

Giovanni is the founder of PT. Starqle Indonesia, a Jakarta-based company providing products, IT consulting, and development services with a focus on the healthcare industry.

Hafiz Badrie Lubis

Hafiz majored in Informatics Engineering at Bandung Institute of Technology, Bandung. He graduated in 2008. In his study period, he spent most of his time researching user interaction. It was a bit contradictive because he worked mainly in backend programming after he graduated. Most of his research was about ActionScript, PHP, and Javascript. About 2 years later, he came across Ruby on Rails, which sparked a lot more interest in web development. His interest was magnified after he took on the role of Chief Technology Officer in a startup (Wiradipa Nusantara) he built with his friends. Since then, most of his time was contributed to research on Ruby, Ruby on Rails, and web performance. He blogs extensively about Ruby and Ruby on Rails at http://hafizbadrie.wordpress.com. He has written a lot about best practices for using Ruby on Rails and also about web performance.

Currently, he is a Lead Developer in The Jakarta Post Digital while maintaining his startup as a CTO in Wiradipa Nusantara. In recent days, he is paying more attention to the development of web performance from the server side with Ruby, the client side with JavaScript, and any other related strategy. He is a member of id-ruby (http://id-ruby.org), an Indonesian community that talks about Ruby and is also a member of Card to Post (http://www.cardtopost.com), an Indonesian community that mainly talks about postcards.

Nia Mutiara

Nia Mutiara is a software engineer working on a virtual stock gaming iOS application, as well as its server-side web application. For two years, she worked on complex Ruby on Rails and iOS applications. She is a master of JavaScript and CSS, and has used those skills to enhance most web applications that she has worked on. In her spare time, she hangs around Twitter, writes Ruby tutorials in Indonesian, and watches comedy.

Books From Packt


Aptana RadRails: An IDE for Rails Development
Aptana RadRails: An IDE for Rails Development

 Ruby on Rails Enterprise Application Development: Plan, Program, Extend
Ruby on Rails Enterprise Application Development: Plan, Program, Extend

 Building Dynamic Web 2.0 Websites with Ruby on Rails
Building Dynamic Web 2.0 Websites with Ruby on Rails

Ruby on Rails Web Mashup Projects
Ruby on Rails Web Mashup Projects

 CoffeeScript Programming with jQuery, Rails, and Node.js
CoffeeScript Programming with jQuery, Rails, and Node.js

 Railo 3 Beginner’s Guide
Railo 3 Beginner’s Guide

OpenAM
OpenAM

Ruby and MongoDB Web Development Beginner's Guide
Ruby and MongoDB Web Development Beginner's Guide


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software