Rails에 대한 착각의 최첨단은 무엇입니까?
사용자의 이메일 주소를 확인하기 위해 무엇을 사용하고 그 이유는 무엇입니까?
validates_email_veracity_of
실제로 MX 서버를 쿼리하는 것을 사용했습니다 . 대부분의 대부분의 네트워크 트래픽 및 안정성과 여러 가지 많은 실패로 가득합니다.
주위를 둘러 보면 보니 많은 사람들이 이메일 주소에 대한 온 전성 검사를 수행하는 데 사용하고 분명한 사실을 찾을 수 없습니다. 사용을 위해 유지되고 있고, 더 많은 사람들이 보유하고 있습니까?
추신 : 이메일이 작동하는지 확인하기 위해 링크가있는 이메일을 보내라고 말하지 않습니다. "친구에게 보내기"기능을 개발 중 출시 실용 지 발표.
Rails 3.0에서는 Mail gem을 사용하여 regexp없이 이메일 유효성 검사를 사용할 수 있습니다 .
필요 이상으로 어렵게 만들지 판결. 귀하의 기능은 중요하지 않습니다. 유효성 검사는 오타를 잡기 기본 온전한 단계 일뿐입니다. 나는 간단한 정규식으로 그것을 할 수 없습니다.
/\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가 기본적으로 이와 같은 것을 포함하지 않습니다.
http://github.com/balexand/email_validator
이 프로젝트에는 현재 github에서 가장 많은 감시자가있는 것입니다 (레일의 이메일 유효성 검사 용).
https://github.com/alexdunae/validates_email_format_of
가에서 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 (최상위 도메인)를 이 목록 에 포함하도록 요구하면 더 엄격해질 수 있지만 새 TLD가 팝업되면 해당 목록을 업데이트해야합니다 (예 : 2012 년 추가 .mobi
및 .tel
).
파서를 직접 연결하는 장점은 Mail 문법 의 규칙 이 Mail gem이 사용하는 부분에 대해 상당히 넓다 user<user@example.com>
는 것입니다. SMTP에 일반적으로 사용 되는 주소를 구문 분석 할 수 있도록 설계되었습니다 . 그것을 소비함으로써 Mail::Address
당신은 많은 추가 검사를해야합니다.
Mail gem에 대한 또 다른 참고 사항은 클래스가 RFC2822이지만 문법에는 RFC5322의 일부 요소가 있습니다 ( 예 : this test) .
Rails 3에서는 재사용 가능한 유효성 검사기 를 작성할 수 있습니다 .
class EmailValidator < ActiveRecord::Validator
def validate()
record.errors[:email] << "is not valid" unless
record.email =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
end
end
다음과 함께 사용하십시오 validates_with
.
class User < ActiveRecord::Base
validates_with EmailValidator
end
다른 답변에 주목하면서 질문은 여전히 남아 있습니다. 왜 그것에 대해 영리하게 생각 하는가?
많은 정규식이 거부하거나 놓칠 수있는 실제 사례의 양은 문제가있는 것처럼 보입니다.
이메일 주소를 '확인'하더라도 실제로 작동하는 이메일 주소인지 확인하는 것은 아닙니다.
regexp를 사용하는 경우 클라이언트 측에 @이 있는지 확인하십시오.
잘못된 이메일 시나리오의 경우 '메시지를 보내지 못했습니다'분기를 코드로 보내십시오.
기본적으로 가장 일반적인 3 가지 옵션이 있습니다.
- 정규 표현식 (일괄적인 전자 메일 주소 정규 표현식이 없으므로 직접 굴림)
- MX 쿼리 (사용하는 것)
- 활성화 토큰 생성 및 우편 발송 (restful_authentication 방식)
validates_email_veracity_of와 토큰 생성을 모두 사용하지 않으려면 구식 정규식 검사를 사용합니다.
Mail gem에는 주소 파서가 내장되어 있습니다.
begin
Mail::Address.new(email)
#valid
rescue Mail::Field::ParseError => e
#invalid
end
이 솔루션은 @SFEley 및 @Alessandro DS의 답변, 리팩터링 및 사용 설명을 기반으로합니다.
다음과 같이 모델에서이 유효성 검사기 클래스를 사용할 수 있습니다.
class MyModel < ActiveRecord::Base
# ...
validates :colum, :email => { :allow_nil => true, :message => 'O hai Mark!' }
# ...
end
app/validators
폴더에 다음이있는 경우 (레일 3) :
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return options[:allow_nil] == true if value.nil?
unless matches?(value)
record.errors[attribute] << (options[:message] || 'must be a valid email address')
end
end
def matches?(value)
return false unless value
if /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/.match(value).nil?
false
else
true
end
end
end
대한 메일 링리스트 확인 . (저는 Rails 4.1.6을 사용합니다)
여기 에서 정규식을 얻었 습니다 . 매우 완벽한 것으로 보이며 수많은 조합에 대해 테스트되었습니다. 해당 페이지에서 결과를 볼 수 있습니다.
Ruby 정규 표현식으로 약간 변경하고 내 lib/validators/email_list_validator.rb
코드는 다음과 같습니다.
require 'mail'
class EmailListValidator < ActiveModel::EachValidator
# Regexp source: https://fightingforalostcause.net/content/misc/2006/compare-email-regex.php
EMAIL_VALIDATION_REGEXP = Regexp.new('\A(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))\z', true)
def validate_each(record, attribute, value)
begin
invalid_emails = Mail::AddressList.new(value).addresses.map do |mail_address|
# check if domain is present and if it passes validation through the regex
(mail_address.domain.present? && mail_address.address =~ EMAIL_VALIDATION_REGEXP) ? nil : mail_address.address
end
invalid_emails.uniq!
invalid_emails.compact!
record.errors.add(attribute, :invalid_emails, :emails => invalid_emails.to_sentence) if invalid_emails.present?
rescue Mail::Field::ParseError => e
# Parse error on email field.
# exception attributes are:
# e.element : Kind of element that was wrong (in case of invalid addres it is Mail::AddressListParser)
# e.value: mail adresses passed to parser (string)
# e.reason: Description of the problem. A message that is not very user friendly
if e.reason.include?('Expected one of')
record.errors.add(attribute, :invalid_email_list_characters)
else
record.errors.add(attribute, :invalid_emails_generic)
end
end
end
end
그리고 모델에서 다음과 같이 사용합니다.
validates :emails, :presence => true, :email_list => true
다른 구분 기호와 synthax를 사용하여 다음과 같은 메일 링리스트의 유효성을 검사합니다.
mail_list = 'John Doe <john@doe.com>, chuck@schuld.dea.th; David G. <david@pink.floyd.division.bell>'
이 정규식을 사용하기 전에을 사용 Devise.email_regexp
했지만 매우 간단한 정규식이며 필요한 모든 경우를 얻지 못했습니다. 일부 이메일이 충돌했습니다.
웹에서 다른 정규식을 시도했지만 지금까지 가장 좋은 결과를 얻었습니다. 귀하의 경우에 도움이되기를 바랍니다.
참고 URL : https://stackoverflow.com/questions/1156601/whats-the-state-of-the-art-in-email-validation-for-rails
'IT' 카테고리의 다른 글
Android Studio 프로젝트에서 .jar를 만드는 방법 (0) | 2020.08.26 |
---|---|
React Router 4에서 인증 된 경로를 구현하는 방법은 무엇입니까? (0) | 2020.08.26 |
관계의 부모-자식 관계를 계층 적 트리로 변환 하시겠습니까? (0) | 2020.08.26 |
임시 분산 쿼리를 활성화하는 방법 (0) | 2020.08.26 |
할당 왼쪽의 자바 개체 대괄호 표기법 ({Navigation} =) (0) | 2020.08.26 |