简体   繁体   中英

Devise - sign in by email OR username

I've done all of the this tutorial: Devise wiki

But when I try to log in I get error in the browser:

SQLite3::SQLException: no such column: users.login: SELECT "users".* FROM "users" WHERE "users"."login" = 'jan12345' ORDER BY "users"."id" ASC LIMIT 1

Where could be a problem? How to debug this?

I don't have login field on the users table but I have username field.

My model file:

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  attr_accessor :login
  protect_from_forgery with: :exception

  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me, :first_name, :last_name, :expiration_date) }
    devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:login, :username, :email, :password, :remember_me) }
  end
end

You're sending the login attribute to the db; you need to make it either username or email , which is done with a combination of both a custom attribute & special lookup, as per the docs :

#app/models/user.rb
class User < ActiveRecord::Base
  #remove attr_accessor :login (it just makes getter/setter methods which we do manually below)

  protected

  def login=(login)
    @login = login
  end

  def login
    @login || self.username || self.email
  end

  private

  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
      else
         where(conditions.to_h).first
      end
  end
end

--

You've done a great job with the sanitizer etc -- what you're doing is taking a single "login" attribute & making Devise use either login , username or email to find the User record.

At present, the error says users.login cannot be found -- this means your Devise install is looking up login (which isn't in your database), when it should be searching through username and email WITH the login attribute.

The second bit of code ( self.find_for_database_authentication ) performs a lookup for Devise . If you read the query, it takes the login attribute and sets it to looking up either username or email . This is missing from your implementation and should be added.

After adding, remember to restart your server.


Update

Your attr_accessor should be in your model (yours is in your controller).

All it does is define a setter and getter method for the attribute you define. It's most commonly referred to as a "virtual" attribute , as it's not saved in the database.

I could tell you about setter / getter methods if required, I'll leave it for now to prevent confusion

In your initializer/devise.rb , write the below code:

config.authentication_keys = [ :username ]

In application controller , write the below code:

 def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username) }
    devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username) }
 end

You do not have to do that much code,

You can check from https://stackoverflow.com/a/55184048/9490901 ,

only replace contact_number to username :

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM