[ruby-on-rails] Rails에 대한 이메일 검증의 최첨단은 무엇입니까?
사용자의 이메일 주소를 확인하기 위해 무엇을 사용하고 있으며 그 이유는 무엇입니까?
validates_email_veracity_of
실제로 MX 서버를 쿼리하는 것을 사용했습니다 . 그러나 이는 대부분 네트워크 트래픽 및 안정성과 관련된 다양한 이유로 실패로 가득 차 있습니다.
주위를 둘러 보니 많은 사람들이 이메일 주소에 대한 온 전성 검사를 수행하는 데 사용하고 있다는 분명한 사실을 찾을 수 없었습니다. 이를 위해 유지되고 합리적으로 정확한 플러그인이나 gem이 있습니까?
추신 : 이메일이 작동하는지 확인하기 위해 링크가있는 이메일을 보내라고 말하지 마십시오. “친구에게 보내기”기능을 개발 중이므로 실용적이지 않습니다.
답변
답변
필요 이상으로 어렵게 만들지 마십시오. 귀하의 기능은 중요하지 않습니다. 유효성 검사는 오타를 잡기위한 기본적인 온전한 단계 일뿐입니다. 나는 간단한 정규식으로 그것을 할 것이고 너무 복잡한 것에 CPU 사이클을 낭비하지 않을 것입니다.
/\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/
이것은 http://www.regular-expressions.info/email.html 에서 수정되었습니다 -모든 장단점을 정말로 알고 싶다면 읽어야합니다. 더 정확하고 훨씬 더 복잡한 RFC822 호환 정규식을 원한다면 그 페이지에도 있습니다. 그러나 문제는 이것이다 : 당신이 그것을 완전히 옳게 할 필요는 없습니다.
주소가 유효성 검사를 통과하면 이메일을 보내 게됩니다. 이메일이 실패하면 오류 메시지가 표시됩니다. 어느 시점에서 사용자에게 “죄송합니다. 친구가받지 못했습니다. 다시 시도 하시겠습니까?” 라고 말할 수 있습니다.직접 검토를 위해 플래그를 지정하거나 무시할 수 있습니다.
이것은 주소 가 그랬 다면 다루어야 할 것과 동일한 옵션입니다. 유효성 검사를 통과 입니다. 유효성 검사가 완벽하고 주소가 존재한다는 절대적인 증거를 획득하더라도 전송이 여전히 실패 할 수 있기 때문입니다.
검증시 오 탐지 비용은 낮습니다. 더 나은 유효성 검사의 이점도 낮습니다. 관대하게 검증하고 오류가 발생하면 걱정하십시오.
답변
Rails 3에서 이메일 유효성 검사를위한 gem을 만들었습니다. Rails가 기본적으로 이와 같은 것을 포함하지 않는다는 사실에 약간 놀랐습니다.
답변
이 프로젝트에는 현재 github에서 가장 많은 감시자가있는 것 같습니다 (레일의 이메일 유효성 검사 용).
답변
가에서 4 문서를 레일 :
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 < ActiveRecord::Base
validates :email, presence: true, email: true
end
답변
Rails 4에서는 모델에 간단히 추가 validates :email, email:true
(필드가라고 가정 email
) 한 다음 단순 (또는 복합 †)을 작성합니다.EmailValidator
필요에 맞게 을 작성하십시오.
예 :-모델 :
class TestUser
include Mongoid::Document
field :email, type: String
validates :email, email: true
end
귀하의 검증 인 (으로 이동 app/validators/email_validator.rb
)
class EmailValidator < ActiveModel::EachValidator
EMAIL_ADDRESS_QTEXT = Regexp.new '[^\\x0d\\x22\\x5c\\x80-\\xff]', nil, 'n'
EMAIL_ADDRESS_DTEXT = Regexp.new '[^\\x0d\\x5b-\\x5d\\x80-\\xff]', nil, 'n'
EMAIL_ADDRESS_ATOM = Regexp.new '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+', nil, 'n'
EMAIL_ADDRESS_QUOTED_PAIR = Regexp.new '\\x5c[\\x00-\\x7f]', nil, 'n'
EMAIL_ADDRESS_DOMAIN_LITERAL = Regexp.new "\\x5b(?:#{EMAIL_ADDRESS_DTEXT}|#{EMAIL_ADDRESS_QUOTED_PAIR})*\\x5d", nil, 'n'
EMAIL_ADDRESS_QUOTED_STRING = Regexp.new "\\x22(?:#{EMAIL_ADDRESS_QTEXT}|#{EMAIL_ADDRESS_QUOTED_PAIR})*\\x22", nil, 'n'
EMAIL_ADDRESS_DOMAIN_REF = EMAIL_ADDRESS_ATOM
EMAIL_ADDRESS_SUB_DOMAIN = "(?:#{EMAIL_ADDRESS_DOMAIN_REF}|#{EMAIL_ADDRESS_DOMAIN_LITERAL})"
EMAIL_ADDRESS_WORD = "(?:#{EMAIL_ADDRESS_ATOM}|#{EMAIL_ADDRESS_QUOTED_STRING})"
EMAIL_ADDRESS_DOMAIN = "#{EMAIL_ADDRESS_SUB_DOMAIN}(?:\\x2e#{EMAIL_ADDRESS_SUB_DOMAIN})*"
EMAIL_ADDRESS_LOCAL_PART = "#{EMAIL_ADDRESS_WORD}(?:\\x2e#{EMAIL_ADDRESS_WORD})*"
EMAIL_ADDRESS_SPEC = "#{EMAIL_ADDRESS_LOCAL_PART}\\x40#{EMAIL_ADDRESS_DOMAIN}"
EMAIL_ADDRESS_PATTERN = Regexp.new "#{EMAIL_ADDRESS_SPEC}", nil, 'n'
EMAIL_ADDRESS_EXACT_PATTERN = Regexp.new "\\A#{EMAIL_ADDRESS_SPEC}\\z", nil, 'n'
def validate_each(record, attribute, value)
unless value =~ EMAIL_ADDRESS_EXACT_PATTERN
record.errors[attribute] << (options[:message] || 'is not a valid email')
end
end
end
이렇게하면 태그를 포함한 모든 종류의 유효한 이메일이 허용됩니다. “test+no_really@test.tes”등과 같은 이메일을 됩니다.
이것을 테스트하려면 rspec
에spec/validators/email_validator_spec.rb
require 'spec_helper'
describe "EmailValidator" do
let(:validator) { EmailValidator.new({attributes: [:email]}) }
let(:model) { double('model') }
before :each do
model.stub("errors").and_return([])
model.errors.stub('[]').and_return({})
model.errors[].stub('<<')
end
context "given an invalid email address" do
let(:invalid_email) { 'test test tes' }
it "is rejected as invalid" do
model.errors[].should_receive('<<')
validator.validate_each(model, "email", invalid_email)
end
end
context "given a simple valid address" do
let(:valid_simple_email) { 'test@test.tes' }
it "is accepted as valid" do
model.errors[].should_not_receive('<<')
validator.validate_each(model, "email", valid_simple_email)
end
end
context "given a valid tagged address" do
let(:valid_tagged_email) { 'test+thingo@test.tes' }
it "is accepted as valid" do
model.errors[].should_not_receive('<<')
validator.validate_each(model, "email", valid_tagged_email)
end
end
end
어쨌든 이것이 내가 한 방법입니다. YMMV
† 정규 표현은 폭력과 같습니다. 작동하지 않으면 충분히 사용하지 않는 것입니다.
답변
Hallelujah가 제안 했듯이 Mail gem을 사용하는 것 같습니다. 을 사용하는 것이 좋은 접근 방식 . 그러나 나는 거기에 몇 가지 농구를 싫어합니다.
나는 사용한다:
def self.is_valid?(email)
parser = Mail::RFC2822Parser.new
parser.root = :addr_spec
result = parser.parse(email)
# Don't allow for a TLD by itself list (sam@localhost)
# The Grammar is: (local_part "@" domain) / local_part ... discard latter
result &&
result.respond_to?(:domain) &&
result.domain.dot_atom_text.elements.size > 1
end
TLD (최상위 도메인)를 이 목록 에 포함하도록 요구하면 더 엄격해질 수 있지만 2012 년 추가 .mobi
및.tel
).
파서를 직접 연결하는 장점은 Mail 문법 의 규칙 이 Mail gem이 사용하는 부분에 대해 상당히 넓다 user<user@example.com>
는 것입니다. SMTP에 일반적으로 사용 되는 주소를 구문 분석 할 수 있도록 설계되었습니다 . 그것을 소비함으로써Mail::Address
당신은 많은 추가 검사를해야합니다.
Mail gem에 대한 또 다른 참고 사항은 클래스가 RFC2822이지만 문법에는 RFC5322의 일부 요소가 있습니다 ( 예 : this test) .