Rails and Devise – Login using either username or email
This is essentially a no-nonsense step-by-step description of the most common case from: https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address
1) add a field to the User table
rails generate migration add_username_to_users username:string:uniq
1b) check that the migration does:
2) apply the migration
rake db:migrate
3) modify app/controllers/application_controller.rb
class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters added_attrs = [:username, :email, :password, :password_confirmation, :remember_me] devise_parameter_sanitizer.permit :sign_up, keys: added_attrs devise_parameter_sanitizer.permit :account_update, keys: added_attrs end end
4a) EITHER add “login” as an attr_accessor on the User model
# Virtual attribute for authenticating by either username or email # This is in addition to a real persisted field like 'username' attr_accessor :login
4b) OR implement the GET and SET yourself
def login=(login) @login = login end def login @login || self.username || self.email end
5a) EITHER tell Devise to GLOBALLY use this “login” virtual attribute
config/initializers/devise.rb config.authentication_keys = [ :login ]
5b) OR specify it on the User model in the “devise” statement
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login]
6) Create a method “find_for_database_authentication” in User model
def self.find_for_database_authentication(warden_conditions) conditions = warden_conditions.dup if login = conditions.delete(:login) where(conditions.to_h).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first elsif conditions.has_key?(:username) || conditions.has_key?(:email) where(conditions.to_h).first end end
NOTE! Read the original post for specific problems and/or details!!! There are some caveats!
7) Add validations on the User model
validates :username, :presence => true, :uniqueness => { :case_sensitive => false } # etc.