IT

Rails에 대한 착각의 최첨단은 무엇입니까?

lottoking 2020. 8. 26. 08:09
반응형

Rails에 대한 착각의 최첨단은 무엇입니까?


사용자의 이메일 주소를 확인하기 위해 무엇을 사용하고 그 이유는 무엇입니까?

validates_email_veracity_of실제로 MX 서버를 쿼리하는 것을 사용했습니다 . 대부분의 대부분의 네트워크 트래픽 및 안정성과 여러 가지 많은 실패로 가득합니다.

주위를 둘러 보면 보니 많은 사람들이 이메일 주소에 대한 온 전성 검사를 수행하는 데 사용하고 분명한 사실을 찾을 수 없습니다. 사용을 위해 유지되고 있고, 더 많은 사람들이 보유하고 있습니까?

추신 : 이메일이 작동하는지 확인하기 위해 링크가있는 이메일을 보내라고 말하지 않습니다. "친구에게 보내기"기능을 개발 중 출시 실용 지 발표.


Rails 3.0에서는 Mail gem을 사용하여 regexp없이 이메일 유효성 검사를 사용할 수 있습니다 .

다음은 내 구현입니다 ( gem 패키지 ).


필요 이상으로 어렵게 만들지 판결. 귀하의 기능은 중요하지 않습니다. 유효성 검사는 오타를 잡기 기본 온전한 단계 일뿐입니다. 나는 간단한 정규식으로 그것을 할 수 없습니다.

/\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"등과 같이 태그가 지정된 이메일을 포함 하여 모든 종류의 이메일을 허용 합니다.

이것을 테스트 결과 rspecspec/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에서는 재사용 가능한 유효성 검사기 를 작성할 수 있습니다 .

http://archives.ryandaigle.com/articles/2009/8/11/what-s-new-in-edge-rails-independent-model-validators

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 가지 옵션이 있습니다.

  1. 정규 표현식 (일괄적인 전자 메일 주소 정규 표현식이 없으므로 직접 굴림)
  2. MX 쿼리 (사용하는 것)
  3. 활성화 토큰 생성 및 우편 발송 (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

반응형