私はRailsでメール検証を行っています:
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
また、フロントエンドでHTML5検証を行いますが、メールアドレスは
[email protected]
[email protected]
まだ有効です。私は何が欠けていますか?
標準のRubyライブラリのURIに組み込まれた定数を使用します
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
メールアドレスの検証に正規表現を使用しないでください。それは罠だ。あなたが考えるよりもはるかに有効なメールアドレス形式があります。しかしながら! mail
gem(ActionMailerに必要なので、持っています)は、適切なパーサーでメールアドレスを解析します:
require 'mail'
a = Mail::Address.new('[email protected]')
準拠していないメールアドレスの場合、これは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
そして、あなたのモデルでは、次のことができます:
include EmailValidatable
validates :email, email: true
以下のIwo Dziechciarowのコメントが言及しているように、これは有効な「To:」アドレスであるものをすべて渡します。したがって、Foo Bar <[email protected]>
のようなものが有効です。これはあなたにとって問題かもしれませんが、そうでないかもしれません。本当には有効なアドレスです。
アドレス部分だけが必要な場合:
a = Mail::Address.new('Foo Bar <[email protected]>')
a.address
=> "[email protected]"
BjörnWeinbrenneが以下に指摘しているように、 RFC2822アドレス は予想よりもはるかに有効です(そこにリストされているアドレスはすべて準拠していると確信しており、システム構成に応じてメールを受信します)—これは正規表現を試すことをお勧めしないが、準拠したパーサーを使用する理由。
メールをアドレスに送信できるかどうかを本当に気にする場合、最善の策は、間違いなく検証リンク付きのメッセージを送信することです
既にアプリでDevise gemを使用している場合は、使用するのが適切かもしれません
email =~ Devise.email_regexp
...これは、アプリの異なる場所で同じ検証が使用されることも意味します。
@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" <[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
>>
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
そして、あなたのモデルでは、次のことができます:
include PrettyEmailValidatable
validates :pretty_email, email: true
そのため、「きれいなメール」の検証には上記を使用し、標準のメールの検証には https://github.com/balexand/email_validator を使用します。
validates_email_format_of gemを試してください。
他の誰かが非常にTDDに焦点を合わせている場合:テストを別のモデルに結び付けずに、必要に応じてテストを作成し、後で改善できるものが必要でした。
Nate および tongueroo のコードの構築(ありがとう Nate および tongueroo !)、これは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
そして、これは決して包括的なものではありませんが、ここに私が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
それが役に立てば幸い!
以下に、メールの検証を行う新しいRailsの方法を示します。
validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
Rails valications doc を参照してください。
簡単な答えは次のとおりです。正規表現を使用しないでください。 Edgeのケースが多すぎて、偽陰性と偽陽性があります。 @記号を確認し、そのアドレスにメールを送信して検証します。
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
!("[email protected]" =~ VALID_EMAIL_REGEX).nil?
Rubyには、メールを検証するための正規表現が組み込まれています。
validates :email, format: {
with: URI::MailTo::EMAIL_REGEXP,
message: 'Only valid emails allowed'
}
これを試すことができます
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
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
現時点ではemail_validatorgemには複雑な検証ルールはありませんが、
/[^\s]@[^\s]/
https://github.com/balexand/email_validator/blob/master/lib/email_validator.rb#L1
引数は https://medium.com/hackernoon/the-100-correct-way-to-validate-email-addresses-7c4818f2464 にあります
これを試して。
validates_format_of :email, :with => /^[\+A-Z0-9\._%-]+@([A-Z0-9-]+\.)+[A-Z]{2,4}$/i