Ruby-on-rails RoR 设计:使用用户名或电子邮件登录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2997179/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
RoR Devise: Sign in with username OR email
提问by Patrick Oscity
What's the best way to enable users to log in with their email address OR their username? I am using warden + devise for authentication. I think it probably won't be too hard to do it but i guess i need some advice here on where to put all the stuff that is needed. Perhaps devise already provides this feature? Like in the config/initializers/devise.rb you would write:
使用户能够使用他们的电子邮件地址或用户名登录的最佳方式是什么?我正在使用warden + devise进行身份验证。我认为这样做可能不会太难,但我想我需要一些关于将所有需要的东西放在哪里的建议。也许设计已经提供了这个功能?就像在 config/initializers/devise.rb 你会写:
config.authentication_keys = [ :email, :username ]
To require both username AND email for signing in. But i really want to have only one field for both username and email and require only one of them. I'll just visualize that with some ASCII art, it should look something like this in the view:
需要用户名和电子邮件才能登录。但我真的希望用户名和电子邮件只有一个字段,并且只需要其中之一。我将使用一些 ASCII 艺术将其形象化,它在视图中应该看起来像这样:
Username or Email:
[____________________]
Password:
[____________________]
[Sign In]
采纳答案by Patrick Oscity
I have found a solution for the problem. I'm not quite satisfied with it (I'd rather have a way to specify this in the initializer), but it works for now. In the user model I added the following method:
我已经找到了解决问题的方法。我对它不太满意(我宁愿有一种方法在初始化程序中指定它),但它现在有效。在用户模型中,我添加了以下方法:
def self.find_for_database_authentication(conditions={})
find_by(username: conditions[:email]) || find_by(email: conditions[:email])
end
As @sguha and @Chetan have pointed out, another great resource is available on the official devise wiki.
正如@sguha 和@Chetan 所指出的,官方设计wiki 上提供了另一个很棒的资源。
回答by Chetan
From their Wiki — How To: Allow users to sign in using their username or email address.
来自他们的 Wiki —如何:允许用户使用他们的用户名或电子邮件地址登录。
回答by Martin Seroczyński
def self.find_for_authentication(conditions)
conditions = ["username = ? or email = ?", conditions[authentication_keys.first], conditions[authentication_keys.first]]
# raise StandardError, conditions.inspect
super
end
回答by aku
Make sure you already added username field and add username to attr_accessible. Create a login virtual attribute in Users
确保您已经添加了用户名字段并将用户名添加到 attr_accessible。在用户中创建登录虚拟属性
1) Add login as an attr_accessor
1) 添加登录作为 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) Add login to attr_accessible
2) 将登录添加到 attr_accessible
attr_accessible :login
Tell Devise to use :login in the authentication_keys
告诉设计在 authentication_keys 中使用 :login
Modify config/initializers/devise.rb to have:
修改 config/initializers/devise.rb 以具有:
config.authentication_keys = [ :login ]
Overwrite Devise's find_for_database_authentication method in Users
覆盖用户中设计的 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
Update your views Make sure you have the Devise views in your project so that you can customize them
更新您的视图确保您的项目中有设计视图,以便您可以自定义它们
remove <%= f.label :email %> remove <%= f.email_field :email %> add <%= f.label :login %> add <%= f.text_field :login %>
remove <%= f.label :email %> remove <%= f.email_field :email %> add <%= f.label :login %> add <%= f.text_field :login %>
回答by Kulbir Saini
https://gist.github.com/867932: One solution for everything. Sign in, forgot password, confirmation, unlock instructions.
https://gist.github.com/867932:一种解决方案。登录、忘记密码、确认、解锁说明。
回答by Mike Jarema
Platforma Tec (devise author) has posted a solution to their github wiki which uses an underlying Warden authentication strategy rather than plugging into the Controller:
Platforma Tec(设计作者)在他们的 github wiki 上发布了一个解决方案,该解决方案使用底层 Warden 身份验证策略,而不是插入控制器:
(An earlier answer had a broken link, which I believe was intended to link to this resource.)
(较早的答案有一个断开的链接,我认为该链接旨在链接到此资源。)
回答by tarmo
With squeelgem you can do:
使用squeelgem,您可以执行以下操作:
def self.find_for_authentication(conditions={})
self.where{(email == conditions[:email]) | (username == conditions[:email])}.first
end
回答by mahemoff
Here's a Rails solution which refactors @padde's answer. It uses ActiveRecord's find_by to simplify the calls, ensures there's only one call based on the regex, and also supports numeric IDs if you want to allow that (useful for scripts/APIs). The regex for email is as simple as it needs to be in this context; just checking for the presence of an @ as I assume your username validtor doesn't allow @ characters.
这是一个 Rails 解决方案,它重构了@padde 的答案。它使用 ActiveRecord 的 find_by 来简化调用,确保只有一个基于正则表达式的调用,并且如果您愿意,还支持数字 ID(对脚本/API 有用)。电子邮件的正则表达式很简单,因为它需要在这种情况下;只是检查 @ 的存在,因为我假设您的用户名验证器不允许 @ 字符。
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
Like the wiki and @aku's answer, I'd also recommend making a new :login parameter using attr_accessible and authentication_keys instead of using :email here. (I kept it as :email in the example to show the quick fix.)
就像维基和@aku 的回答一样,我还建议使用 attr_accessible 和 authentication_keys 来创建一个新的 :login 参数,而不是在这里使用 :email 。(我在示例中将其保留为 :email 以显示快速修复。)
回答by maverick
I wrote like this and it works out. Don't know if it's "ugly fix", but if I'll come up with a a better solution I'll let you know...
我是这样写的,效果很好。不知道这是否是“丑陋的修复”,但如果我能想出更好的解决方案,我会让你知道......
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
回答by amit_saxena
I use a quick hack for this, to avoid changing any devise specific code and use it for my specific scenario (I particularly use it for an API where mobile apps can create users on the server).
我为此使用了一个快速 hack,以避免更改任何设计特定的代码并将其用于我的特定场景(我特别将它用于移动应用程序可以在服务器上创建用户的 API)。
I have added a before_filter to all the devise controllers where if username is being passed, I generate an email from the username ("#{params[:user][:username]}@mycustomdomain.com") and save the user. For all other calls as well, I generate the email based on same logic. My before_filter looks like this:
我在所有设备控制器中添加了一个 before_filter,如果用户名被传递,我会从用户名(“#{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
I am also saving username in the users table, so I know that users with email ending in @mycustomdomain.com were created using username.
我还将用户名保存在用户表中,因此我知道电子邮件以 @mycustomdomain.com 结尾的用户是使用用户名创建的。

