Charlie Massry

Devise on Rails

October 07, 2014

With most web apps, you’ll want to have some type of authentication system so your users’ data is secure. The question then shifts of how to implement user authentication, while you can roll your own, like I described in an earlier post, it can become a time sink really quickly but fortunately there’s a gem for that. There are actually many gems for authentication, in fact, if you look at the Ruby Toolbox page, there are 19 to be exact. Topping the charts is the popular gem Devise from our friends over at Plataformatec in Brazil.

Devise provides many features and has 10 different modules such as the Omniauth support. It can however be difficult to set up, and even the documentation explicitly states to look into how authentication works in Rails and provides some links to sources that detail how to roll your own. To get started, add to your Gemfile

gem "devise"

Next run the Devise generate command

$ rails generate devise:install

This generates two files, config/initializers/devise.rb and config/locales/devise.en.yml. devise.rb holds different configuration values, such as password length or email validation and devise.en.yml holds different Devise messages such as confirmation instructions. Now that you have these files, you can create users. You can call your users anything you want, but if you are just getting started you would probably just want to call them users. To do that you must make sure your database is created and then you can generate your User model with Devise.

$ rails generate devise User

This generates a couple of files, the migration and the User model. When you check the migration you will see a lot of cool database columns that will be created and auto-tracked, such as from the Trackable module, like last_sign_in_ip or last_sign_in_at. You can add your own as you please like username or first_name and last_name for example. This however requires some configuration due to the Strong Params in Rails 4. For example, lets add first name and last name support for the users. In our created migration

class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table(:users) do |t|
      ...
      t.string :first_name
      t.string :last_name
      ...
    end
    ...
  end
end

Now that we’ve finished the migration

$ rake db:migrate

To add the new columns to our view forms we must enter into the forms located in app/views/devise/registrations/new.html.erb. To even see the Devise created views within your app enter

$ rails generate devise:views

This creates the Devise views in the views/devise directory.

Within the form_for block add

<div>
  <%= f.label :first_name %>
  <%= f.text_field :first_name %>
</div>
<div>
  <%= f.label :last_name %>
  <%= f.text_field :last_name %>
</div>

When we submit this form however, it will not work because of the Strong Parameters I mentioned earlier, which really highlights what I think is one of the main problems with Devise, as opposed to a simpler gem like Monban, it hides too much of what is going on which makes modification difficult. To add the first name and last name fields, we won’t create a Devise controller like we did with the views, instead we will modify the ApplicationController with a before_action to modify a hidden Devise controller

class ApplicationController < ActionController::Base
  ...
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) << [:first_name, :last_name]
  end
end

You can create your own controller using the Devise controller generator which you might want to switch to if your application grows and needs more customization or different types of users with different sign in processes. But for now, your User model is ready to roll with Devise and any extra fields you care to add to users.