Has*_*mad 46 ruby email ruby-on-rails
我在Rails中进行电子邮件验证:
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
Run Code Online (Sandbox Code Playgroud)
此外,我在前端进行HTML5验证,但电子邮件地址如
..abc@gmail.com
.abc@gmail.com
Run Code Online (Sandbox Code Playgroud)
仍然有效.我错过了什么?
Jos*_*ter 132
我在标准的ruby库中使用常量内置的URI
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
Run Code Online (Sandbox Code Playgroud)
Nat*_*ate 20
不要使用正则表达式进行电子邮件地址验证.这是一个陷阱.有比您想象的更有效的电子邮件地址格式.然而!该mail宝石(它是由要求的ActionMailer,让你拥有它)会解析电子邮件地址-一个合适解析器-为您提供:
require 'mail'
a = Mail::Address.new('foo@example.com')
Run Code Online (Sandbox Code Playgroud)
Mail::Field::ParseError如果这是一个不合规的电子邮件地址,这将抛出一个.(我们没有涉及到进行MX地址查找等任何事情.)
如果您想获得良好的'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
Run Code Online (Sandbox Code Playgroud)
然后在您的模型中,您可以:
include EmailValidatable
validates :email, email: true
Run Code Online (Sandbox Code Playgroud)
正如Iwo Dziechciarow在下面提到的评论所提到的,这传递了任何有效的"To:"地址.所以类似的东西Foo Bar <foo.bar@example.com>是有效的.这对你来说可能是个问题,也可能不是; 毕竟,它确实是一个有效的地址.
如果你只想要它的地址部分:
a = Mail::Address.new('Foo Bar <foobar@example.com>')
a.address
=> "foobar@example.com"
Run Code Online (Sandbox Code Playgroud)
正如BjörnWeinbrenne在下面指出的那样,有更多有效的RFC2822地址比你预期的更多(我很确定那里列出的所有地址都是兼容的,并且可能根据系统配置接收邮件) - 这就是为什么我不建议尝试正则表达式,但使用兼容的解析器.
如果你真的在乎你是否可以发送电子邮件到一个地址,那么你最好的选择 - 到目前为止 - 实际上是发送带有验证链接的邮件.
Mar*_* T. 13
如果您已在应用中使用Devise gem,则可能适合使用
email =~ Devise.email_regexp
Run Code Online (Sandbox Code Playgroud)
...这也意味着应用程序的不同位置使用相同的验证.
Cyz*_*far 10
这是进行电子邮件验证的新 Rails 方式:
validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
Run Code Online (Sandbox Code Playgroud)
请参阅Rails 验证文档。
@Nate非常感谢您将这个答案放在一起.在我查看您的代码片段之前,我没有意识到电子邮件验证有如此多的细微差别.
我注意到当前邮件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" <jon@doe.com>')
=> #<Mail::Address:70343691638900 Address: |Jon Doe <jon@doe.com>| >
>> a.address
=> "jon@doe.com"
>> 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
>>
Run Code Online (Sandbox Code Playgroud)
它确实会引发Mail::Field::ParseError错误"Jon Doe <jon.我相信也会检查简单的"abc模式".
在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
Run Code Online (Sandbox Code Playgroud)
然后在您的模型中,您可以:
include PrettyEmailValidatable
validates :pretty_email, email: true
Run Code Online (Sandbox Code Playgroud)
所以我使用上面的"漂亮的电子邮件"验证和https://github.com/balexand/email_validator进行标准的电子邮件验证.
如果其他人非常注重TDD:我希望我可以针对这些东西编写测试,并在以后需要时进行改进,而无需将测试与其他模型捆绑在一起。
建立在Nate和Tangeroo的代码(感谢Nate和Tangeroo!)的基础上,在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
Run Code Online (Sandbox Code Playgroud)
这绝不是全面的,但这是我提出的内容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
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你!
最好遵循 Rails 文档:
https://guides.rubyonrails.org/active_record_validations.html#custom-validators
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
record.errors[attribute] << (options[:message] || "is not an email")
end
end
end
class Person < ApplicationRecord
validates :email, presence: true, email: true
end
Run Code Online (Sandbox Code Playgroud)