Replace Users with Devise

30 Jul 2018 . Rails . Comments #authentication

I rolled my own authentication for Praybook. There was a complex single table inheritance design that enabled someone to try out Praybook without signing up. If someone tracked their prayers, and wanted to save their experience, they could sign up and log in from another device.

Now, I want to include email integration for password reset. At this point rolling my own authentication is no longer taking less time than relying on Devise, the de facto Rails solution to Authentication.

The implementation included a relationship between users through a join table that relates Users to Persons. Persons are the pre-member class that elevates to users.

First, to get ActiveModel has_secure_password migrated to Devise, the table must rename password_digest to encrypted_password. This will allow Devise users to log in with existing passwords.

class PersonDevisePassword < ActiveRecord::Migration[5.1]
  def change
    remove_column :person, :encrypted_password
    rename_column :person, :password_digest, :encrypted_password
  end
end

I had a LoginsController that called authenticate on a selected user. Devise uses a SessionsController that is paired well with my login action. I simply replaced form_for :login with form_for :user and changed the form’s action. Devise’s wiki gives complete instructions

<%= form_for :user,
  { url: session_path(:user),
    layout: :inline,
    html: {class: "navbar-form navbar-right"}} do |login_form| %>

My home page relies on the @user variable being populated by the controller, either a new Person or the currently logged in user. My method current_user needs to be removed, and @user assigned to either Devise current_user or a new Person (assigned to the session).

    <% if !user_signed_in? && current_page?(root_path)%>  

Now the sign in is shown when Devise says the user is logged in. Not surprisingly, my Log Out button no longer works.

<%= link_to('Logout', destroy_user_session_path, method: :delete, class: "nav-link pb-navbar-link") %>

Additionally, we need to configure ActionMailer. I am using gmail for development so changing config/environments/development.rb is sufficient.

config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  address: "smtp.gmail.com",
  port: 587,
  domain: ENV["GMAIL_DOMAIN"],
  authentication: "plain",
  enable_starttls_auto: true,
  user_name: ENV["GMAIL_USERNAME"],
  password: ENV["GMAIL_PASSWORD"]
}

Even with a complicated User story with roll-your-own authentication, moving to Devise is an easy process.