RoRdevise:用用户名或电子邮件login

什么是让用户用他们的电子邮件地址或用户名login的最佳方式? 我正在使用warden + devise进行身份validation。 我认为这可能不会太难,但我想我需要一些build议,在哪里把所有需要的东西。 也许devise已经提供了这个function? 就像在config / initializers / devise.rb中你可以这样写:

config.authentication_keys = [ :email, :username ] 

要求用户名和电子邮件login。但我真的只想有一个领域的用户名和电子邮件,只需要其中之一。 我将用一些ASCII艺术来形象化,在视图中应该看起来像这样:

 Username or Email: [____________________] Password: [____________________] [Sign In] 

我find了解决问题的办法。 我不是很满意它(​​我宁愿有一种方法来指定这个在初始化),但它现在工作。 在用户模型中,我添加了以下方法:

 def self.find_for_database_authentication(conditions={}) find_by(username: conditions[:email]) || find_by(email: conditions[:email]) end 

正如@sguha和@Chetan所指出的那样, 另外一个很好的资源可以在官方的wiki上find 。

从他们的维基百科 – 如何:允许用户使用他们的用户名或电子邮件地址login 。

 def self.find_for_authentication(conditions) conditions = ["username = ? or email = ?", conditions[authentication_keys.first], conditions[authentication_keys.first]] # raise StandardError, conditions.inspect super end 

用他们的例子!

确保您已经添加了用户名字段并将用户名添加到attr_accessible。 在用户中创build一个login虚拟属性

1)添加login作为attr_accessor

 # Virtual attribute for authenticating by either username or email # This is in addition to a real persisted field like 'username' attr_accessor :login 

2)添加login到attr_accessible

 attr_accessible :login 

告诉Devise使用:在authentication_keys中login

修改configuration/初始化/ devise.rb有:

 config.authentication_keys = [ :login ] 

在用户中覆盖Devise的find_for_database_authentication方法

 # Overrides the devise method find_for_authentication # Allow users to Sign In using their username or email address def self.find_for_authentication(conditions) login = conditions.delete(:login) where(conditions).where(["username = :value OR email = :value", { :value => login }]).first end 

更新您的视图确保您的项目中有Devise视图,以便您可以自定义它们

 remove <%= f.label :email %> remove <%= f.email_field :email %> add <%= f.label :login %> add <%= f.text_field :login %> 

https://gist.github.com/867932 :一切的解决scheme。 login,忘记密码,确认,解锁说明。

Platforma Tec(devise作者)已经向他们的github wiki发布了一个解决scheme,该解决scheme使用底层的Warden身份validation策略,而不是插入到Controller中:

https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address

(以前的答案有一个断开的链接,我相信这是打算链接到这个资源。)

如果您正在使用MongoDB (使用MongoId),则需要以不同的方式进行查询:

  def self.find_for_database_authentication(conditions={}) self.any_of({name: conditions[:email]},{email: conditions[:email]}).limit(1).first end 

就这样它会在网上的某个地方。

尖叫gem你可以做到:

  def self.find_for_authentication(conditions={}) self.where{(email == conditions[:email]) | (username == conditions[:email])}.first end 

我是这样写的,它可以解决问题。 不知道这是不是“丑陋的修复”,但如果我想出一个更好的解决scheme,我会让你知道…

  def self.authenticate(email, password) user = find_by_email(email) || username = find_by_username(email) if user && user.password_hash = BCrypt::Engine.hash_secret(password, user.password_salt) user else nil end end 

我使用了一个快速入侵的方法,以避免更改任何devise特定的代码,并将其用于我的特定场景(我特别将它用于移动应用程序可以在服务器上创build用户的API)。

我已经添加了一个before_filter所有的devise控制器,如果用户名被传递,我从用户名(“#{params [:user] [:username]} @ mycustomdomain.com”)生成一封电子邮件并保存用户。 对于所有其他调用,我也基于相同的逻辑生成电子邮件。 我的before_filter看起来像这样:

 def generate_email_for_username return if(!params[:user][:email].blank? || params[:user][:username].blank?) params[:user][:email] = "#{params[:user][:username]}@mycustomdomain.com" end 

我也在用户表中保存用户名,所以我知道以@ mycustomdomain.com结尾的用户是使用用户名创build的。

这是一个Rails解决scheme,它重构@ padde的答案。 它使用ActiveRecord的find_by来简化调用,确保只有一个基于正则expression式的调用,并且还支持数字ID,如果你想允许(对脚本/ API有用)。 电子邮件的正则expression式就像在这种情况下一样简单。 只是检查@的存在,因为我认为你的用户名validator不允许@字符。

 def self.find_for_database_authentication(conditions={}) email = conditions[:email] if email =~ /@/ self.find_by_email(email) elsif email.to_s =~ /\A[0-9]+\z/ self.find(Integer(email)) else self.find_by_username(email]) end end 

就像wiki和@ aku的回答一样,我也build议使用attr_accessible和authentication_keys来创build一个新的login参数,而不是使用:email here。 (我保留它:在示例中的电子邮件,以显示快速修复。)