Search code examples
ruby-on-railsauthlogicdevise

Migrating from Authlogic to Devise


I've previously implemented Authlogic for authorization on my site. Now however I wish to switch over to using Devise instead, and I'm wondering if anyone has any experience with this. Perhaps anyone's seen a blog post on the subject?

Thank you.


Solution

  • I myself switched from Authlogic to Devise recently and also didn't find any articles. However, in the simple case, once you've thrown away all of your user_session and other authlogic-related code, the main piece of work is converting your old users table to the format expected by devise.

    My old table looked like this:

          Column       |           Type           |                     Modifiers                      
    -------------------+--------------------------+----------------------------------------------------
     id                | integer                  | not null default nextval('users_id_seq'::regclass)
     login             | character varying(256)   | not null
     password          | character varying(64)    | not null
     created_at        | timestamp with time zone | not null
     updated_at        | timestamp with time zone | not null
     persistence_token | character varying(255)   | not null
    Indexes:
        "users_pkey" PRIMARY KEY, btree (id)
        "index_users_on_persistence_token" UNIQUE, btree (persistence_token)
        "users_login_key" UNIQUE, btree (login)
    

    and I determined that the table would have to contain at least the following info for devise (with many optional features enabled):

     id                   | integer                     | not null default nextval('contributors_id_seq'::regclass)
     email                | character varying(255)      | not null default ''::character varying
     encrypted_password   | character varying(128)      | not null default ''::character varying
     password_salt        | character varying(255)      | not null default ''::character varying
     confirmation_token   | character varying(255)      | 
     confirmed_at         | timestamp without time zone | 
     confirmation_sent_at | timestamp without time zone | 
     reset_password_token | character varying(255)      | 
     remember_token       | character varying(255)      | 
     remember_created_at  | timestamp without time zone | 
     sign_in_count        | integer                     | default 0
     current_sign_in_at   | timestamp without time zone | 
     last_sign_in_at      | timestamp without time zone | 
     current_sign_in_ip   | character varying(255)      | 
     last_sign_in_ip      | character varying(255)      | 
     failed_attempts      | integer                     | default 0
     unlock_token         | character varying(255)      | 
     locked_at            | timestamp without time zone | 
     created_at           | timestamp without time zone | 
     updated_at           | timestamp without time zone | 
    

    So I defined an unadorned activerecord class in the migration class

     class ConversionUser < ActiveRecord::Base
       set_table_name "users"
     end
    

    and then here's the "up" migration code I ended up using (with PostgreSQL):

    add_column :users, :email, :string, :limit => 255
    execute "UPDATE users SET email = login || '@somedomain.net'"
    execute "ALTER TABLE users ALTER email SET NOT NULL"
    
    add_column :users, :encrypted_password, :string, :limit => 128
    add_column :users, :password_salt, :string, :limit => 255
    
    require 'devise/encryptors/bcrypt'
    ConversionUser.find(:all).each do |u|
      password_salt = Devise::Encryptors::Bcrypt.salt(Devise.stretches)
      u.update_attributes!(:password_salt => password_salt,
                           :encrypted_password => Devise::Encryptors::Bcrypt.digest(u.password, Devise.stretches, password_salt, Devise.pepper))
    end
    
    add_column :users, :confirmation_token, :string, :limit => 255
    add_column :users, :confirmed_at, :timestamp
    add_column :users, :confirmation_sent_at, :timestamp
    execute "UPDATE users SET confirmed_at = created_at, confirmation_sent_at = created_at"
    add_column :users, :reset_password_token, :string, :limit => 255
    
    add_column :users, :remember_token, :string, :limit => 255
    add_column :users, :remember_created_at, :timestamp
    add_column :users, :sign_in_count, :integer, :default => 0
    add_column :users, :current_sign_in_at, :timestamp
    add_column :users, :last_sign_in_at, :timestamp
    add_column :users, :current_sign_in_ip, :string, :limit => 255
    add_column :users, :last_sign_in_ip, :string, :limit => 255
    
    add_column :users, :failed_attempts, :integer, :default => 0
    add_column :users, :unlock_token, :string, :limit => 255
    add_column :users, :locked_at, :timestamp
    
    remove_column :users, :password
    remove_column :users, :persistence_token
    
    add_index :users, :email,                :unique => true
    add_index :users, :confirmation_token,   :unique => true
    add_index :users, :reset_password_token, :unique => true
    add_index :users, :unlock_token,         :unique => true
    

    Note that here I've converted a plain password column into a bcrypt-encrypted column for Devise -- if you've used encrypted passwords with Authlogic, then you'll probably want to just rename the column (if necessary) and choose the correct encryptor module in config/initializers/devise.rb.

    For reference, the "devise" clause in my User model looks like this:

    devise :database_authenticatable, :registerable, :recoverable,
      :rememberable, :trackable, :validatable, :confirmable, :lockable,
      :timeoutable, :authentication_keys => [ :login ]
    

    Note that overriding :authentication_keys like this so that users sign in with their login rather than their email address required me to modify some of the devise views: rails generate devise:views, then edit the files.

    Hope this helps a bit. Good luck!