Ruby on Rails 中的电子邮件验证?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38611405/
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
Email validation in Ruby on Rails?
提问by Haseeb Ahmad
I am doing email validation in Rails with:
我正在 Rails 中进行电子邮件验证:
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
Also, I do HTML5 validation in the frontend but email addresses like
此外,我在前端进行 HTML5 验证,但电子邮件地址如
[email protected]
[email protected]
still are valid. What am I missing?
仍然有效。我错过了什么?
回答by Joshua Hunter
I use the constant built into URI in the standard ruby library
我使用标准 ruby 库中内置的常量
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
回答by Nate
Update: I just found the valid_email2gem which looks pretty great.
更新:我刚刚找到了看起来非常棒的valid_email2gem。
Don't use a regular expression for email address validation. It's a trap. There are way more valid email address formats than you'll think of. However! The mailgem (it's required by ActionMailer, so you have it) will parse email addresses — with a proper parser — for you:
不要使用正则表达式进行电子邮件地址验证。这是一个陷阱。有效的电子邮件地址格式比您想象的要多得多。然而!该mail宝石(它是由要求的ActionMailer,让你拥有它)会解析电子邮件地址-一个合适解析器-为您提供:
require 'mail'
a = Mail::Address.new('[email protected]')
This will throw a Mail::Field::ParseErrorif it's a non-compliant email address. (We're not getting into things like doing an MX address lookup or anything.)
Mail::Field::ParseError如果它是一个不合规的电子邮件地址,这将抛出一个。(我们不会进行诸如 MX 地址查找之类的事情。)
If you want the good ol' Rails validator experience, you can make app/models/concerns/email_validatable.rb:
如果您想要良好的 ol' Rails 验证器体验,您可以app/models/concerns/email_validatable.rb:
require 'mail'
module EmailValidatable
extend ActiveSupport::Concern
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
begin
a = Mail::Address.new(value)
rescue Mail::Field::ParseError
record.errors[attribute] << (options[:message] || "is not an email")
end
end
end
end
and then in your model, you can:
然后在您的模型中,您可以:
include EmailValidatable
validates :email, email: true
As Iwo Dziechciarow's comment below mentions, this passes anything that's a valid "To:" address through. So something like Foo Bar <[email protected]>is valid. This might be a problem for you, it might not; it really isa valid address, after all.
正如下面 Iwo Dziechciarow 的评论所提到的,这会传递任何有效的“收件人:”地址。所以类似的东西Foo Bar <[email protected]>是有效的。这对你来说可能是个问题,也可能不是;毕竟,它确实是一个有效的地址。
If you do want just the address portion of it:
如果您只想要它的地址部分:
a = Mail::Address.new('Foo Bar <[email protected]>')
a.address
=> "[email protected]"
As Bj?rn Weinbrenne notes below, there are way more valid RFC2822 addressesthan you may expect (I'm quite sure all of the addresses listed there are compliant, and may receive mail depending system configurations) — this is why I don't recommend trying a regex, but using a compliant parser.
正如 Bj?rn Weinbrenne 在下面指出的那样,有效的RFC2822 地址比您预期的要多得多(我很确定那里列出的所有地址都符合要求,并且可能会根据系统配置接收邮件)——这就是我不这样做的原因建议尝试使用正则表达式,但使用兼容的解析器。
If you really care whether you can send email to an address then your best bet — by far — is to actually send a message with a verification link.
如果您真的关心是否可以向某个地址发送电子邮件,那么到目前为止,您最好的选择是实际发送带有验证链接的消息。
回答by Martin T.
If you use the Devise gem already in your app, it might be opportune to use
如果你已经在你的应用程序中使用了 Devise gem,那么使用它可能是合适的
email =~ Devise.email_regexp
...which also means different places of the app use the same validation.
...这也意味着应用程序的不同位置使用相同的验证。
回答by tongueroo
@Nate Thank you so much for putting this answer together. I did not realize email validation had so many nuances until I looked at your code snippet.
@Nate 非常感谢您将这个答案放在一起。在查看您的代码片段之前,我没有意识到电子邮件验证有这么多细微差别。
I noticed that the current mail gem: mail-2.6.5 doesn't throw an error for an email of "abc". Examples:
我注意到当前的邮件 gem:mail-2.6.5 不会为“abc”的电子邮件引发错误。例子:
>> a = Mail::Address.new('abc')
=> #<Mail::Address:70343701196060 Address: |abc| >
>> a.address # this is weird
=> "abc"
>> a = Mail::Address.new('"Jon Doe" <[email protected]>')
=> #<Mail::Address:70343691638900 Address: |Jon Doe <[email protected]>| >
>> a.address
=> "[email protected]"
>> a.display_name
=> "Jon Doe"
>> Mail::Address.new('"Jon Doe <jon')
Mail::Field::ParseError: Mail::AddressList can not parse |"Jon Doe <jon|
Reason was: Only able to parse up to "Jon Doe <jon
from (irb):3:in `new'
from (irb):3
>>
It does throw Mail::Field::ParseErrorerrors for "Jon Doe <jonwhich is great. I believe will check for the simple "abc pattern" also.
它确实会抛出Mail::Field::ParseError错误,"Jon Doe <jon这很好。我相信也会检查简单的“abc 模式”。
In app/models/concerns/pretty_email_validatable.rb:
在app/models/concerns/pretty_email_validatable.rb:
require 'mail'
module PrettyEmailValidatable
extend ActiveSupport::Concern
class PrettyEmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
begin
a = Mail::Address.new(value)
rescue Mail::Field::ParseError
record.errors[attribute] << (options[:message] || "is not an email")
end
# regexp from http://guides.rubyonrails.org/active_record_validations.html
value = a.address
unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
record.errors[attribute] << (options[:message] || "is not an email")
end
end
end
end
and then in your model, you can:
然后在您的模型中,您可以:
include PrettyEmailValidatable
validates :pretty_email, email: true
So I use the above for "pretty email" validation and the https://github.com/balexand/email_validatorfor standard email validation.
所以我使用上面的“漂亮的电子邮件”验证和https://github.com/balexand/email_validator进行标准的电子邮件验证。
回答by Cyzanfar
Here is the new rails way to do email validation:
这是进行电子邮件验证的新 Rails 方式:
validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
Refer to the Rails valications doc.
请参阅Rails 验证文档。
回答by Hyman Barry
If anybody else is very TDD focused: I wanted something that I could write tests against and improve upon later if needed, without tying the tests to another model.
如果其他人非常关注 TDD:我想要一些我可以编写测试并在以后需要时改进的东西,而不会将测试绑定到另一个模型。
Building off of Nateand tongueroo's code (Thanks Nateand tongueroo!), this was done in Rails 5, Ruby 2.4.1. Here's what I threw into app/validators/email_validator.rb:
基于Nate和舌头的代码构建(感谢Nate和舌头!),这是在Rails 5,中完成的Ruby 2.4.1。这是我投入的内容app/validators/email_validator.rb:
require 'mail'
class EmailValidator < ActiveModel::EachValidator
def add_error(record, attribute)
record.errors.add(attribute, (options[:message] || "is not a valid email address"))
end
def validate_each(record, attribute, value)
begin
a = Mail::Address.new(value)
rescue Mail::Field::ParseError
add_error(record, attribute)
end
# regexp from http://guides.rubyonrails.org/active_record_validations.html
value = a.address unless a.nil?
unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
add_error(record, attribute)
end
end
end
And this is by no means comprehensive, but here's what I threw into spec/validators/email_validator_spec.rb:
这绝不是全面的,但这是我投入的内容spec/validators/email_validator_spec.rb:
require 'rails_helper'
RSpec.describe EmailValidator do
subject do
Class.new do
include ActiveModel::Validations
attr_accessor :email
validates :email, email: true
end.new
end
context 'when the email address is valid' do
let(:email) { Faker::Internet.email }
it 'allows the input' do
subject.email = email
expect(subject).to be_valid
end
end
context 'when the email address is invalid' do
let(:invalid_message) { 'is not a valid email address' }
it 'invalidates the input' do
subject.email = 'not_valid@'
expect(subject).not_to be_valid
end
it 'alerts the consumer' do
subject.email = 'notvalid'
subject.valid?
expect(subject.errors[:email]).to include(invalid_message)
end
end
end
Hope it helps!
希望能帮助到你!
回答by thaleshcv
Try validates_email_format_ofgem.
回答by Martin T.
The simple answer is: Don't use a regexp. There are too many edge cases and false negatives and false positives. Check for an @ sign and send a mail to the address to validate it:
简单的答案是:不要使用正则表达式。有太多的边缘情况和假阴性和假阳性。检查 @ 符号并向该地址发送邮件以进行验证:
回答by A H K
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
!("[email protected]" =~ VALID_EMAIL_REGEX).nil?
回答by gayavat
Please, be aware that for now email_validatorgem does not have complex validation rules, but only:
请注意,目前email_validatorgem 没有复杂的验证规则,但只有:
/[^\s]@[^\s]/
https://github.com/balexand/email_validator/blob/master/lib/email_validator.rb#L13
https://github.com/balexand/email_validator/blob/master/lib/email_validator.rb#L13
Argumentation is in https://medium.com/hackernoon/the-100-correct-way-to-validate-email-addresses-7c4818f24643
论证在https://medium.com/hackernoon/the-100-correct-way-to-validate-email-addresses-7c4818f24643

