⬆️ ⬇️

Ruby: about email in general and for the sake of validation without regexp, in particular

image



Hi Habr!



Few observations.



')

On the proposed issue of parchment is written inadmissibly much. Nevertheless, I would like to stop at three important, but ignored attributes, peculiar to email, from the point of web development.

First email is unique, unlike the nickname, which, in half of the cases, is occupied by someone before us. However, there are still sites with a login by nickname, which, for all such sites, I don’t remember. I suggest to use only email for login.

Secondly, some developers ignore type = 'email' when JS validators are set on this field, and tablet devices switch layouts, which is convenient.

Thirdly, for the sake of what this article is, every year they write articles like “Why is it bad to validate regexp”, which is more like a fetish. I hope Google will index correctly.



Actually the whole preamble for the sake of one interesting solution, which should help Ruby-Stam, it is possible that in other languages ​​this method is also implementable.







Actually, when the problem was first formulated in my head as a problem, I used Google, and in two or three clicks I came across a solution that I use so far. Important: the decision is brazenly styled and given for its own, and if someone finds a link to the source, I will gladly insert it into the article.



The first indicator of validity





gem 'mail' ancient as a world hedge library

require 'mail' mail = Mail::Addres.new('antiqe@gmail.com') mail.local #antiqe mail.domain #gmail.com 


This is the first thing to do.

If the mail address contains invalid characters, the library will call exception, which must be caught. However, nothing is clear to us about the domain, and the domain here may be invalid.



The second indicator of validity





 mail = Mail::Address.new('antiqe@gmail.com') => #<Mail::Address:72490440 Address: |antiqe@gmail.com| > tree = mail.__send__(:tree) => SyntaxNode+Address1+AddrSpec0 offset=0, "antiqe@gmail.com" (dig_comments,comments,local_part,domain): SyntaxNode+LocalDotAtom0 offset=0, "antiqe" (local_dot_atom_text): SyntaxNode+CFWS1 offset=0, "": SyntaxNode offset=0, "" SyntaxNode offset=0, "" SyntaxNode offset=0, "antiqe": SyntaxNode+LocalDotAtomText0 offset=0, "antiqe" (domain_text): SyntaxNode offset=0, "" SyntaxNode offset=0, "antiqe": SyntaxNode offset=0, "a" SyntaxNode offset=1, "n" SyntaxNode offset=2, "t" SyntaxNode offset=3, "i" SyntaxNode offset=4, "q" SyntaxNode offset=5, "e" SyntaxNode+CFWS1 offset=6, "": SyntaxNode offset=6, "" SyntaxNode offset=6, "" SyntaxNode offset=6, "@" SyntaxNode+DotAtom0 offset=7, "gmail.com" (dot_atom_text): SyntaxNode+CFWS1 offset=7, "": SyntaxNode offset=7, "" SyntaxNode offset=7, "" SyntaxNode offset=7, "gmail.com": SyntaxNode+DotAtomText0 offset=7, "gmail." (domain_text): SyntaxNode offset=7, "gmail": SyntaxNode offset=7, "g" SyntaxNode offset=8, "m" SyntaxNode offset=9, "a" SyntaxNode offset=10, "i" SyntaxNode offset=11, "l" SyntaxNode offset=12, "." SyntaxNode+DotAtomText0 offset=13, "com" (domain_text): SyntaxNode offset=13, "com": SyntaxNode offset=13, "c" SyntaxNode offset=14, "o" SyntaxNode offset=15, "m" SyntaxNode offset=16, "" SyntaxNode+CFWS1 offset=16, "": SyntaxNode offset=16, "" SyntaxNode offset=16, "" 




We have a syntactic tree here, the nature and properties of which, for me, are a little less than completely incomprehensible. I only know that the syntax tree, in contrast to regexp, is not recursive in nature.

One can only assume that the creators of the library knew something, but did not say everything.

This tree gives us the opportunity to answer one important question: how many elements does a domain consist of? And if there are more than one such elements, the domain is valid.



Private implementation





In the rails, this is enough:

 require 'mail' class EmailValidator < ActiveModel::EachValidator def validate_each(record,attribute,value) begin address = Mail::Address.new(value) result = address.domain && address.address == value # ,     Mail       email tree = address.__send__(:tree) result &&= (tree.domain.dot_atom_text.elements.size > 1) #    ,       rescue Exception => e #  ,        result = false end record.errors[attribute] << (options[:message] || "is invalid") unless result end end 




put in app / validators / email_validator.rb to use in any model:



 validates :email, :presence => true, :email => true 




False-invalid or false-positive addresses for more than two years have not been identified.

Nothing more to say.

All good.

Source: https://habr.com/ru/post/175399/



All Articles