-
-
Save jcf/1188367 to your computer and use it in GitHub Desktop.
require 'mail' | |
class EmailValidator < ActiveModel::EachValidator | |
attr_reader :record, :attribute, :value, :email, :tree | |
def validate_each(record, attribute, value) | |
@record, @attribute, @value = record, attribute, value | |
@email = Mail::Address.new(value) | |
@tree = email.__send__(:tree) | |
add_error unless valid? | |
rescue Mail::Field::ParseError | |
add_error | |
end | |
private | |
def valid? | |
!!(domain_and_address_present? && domain_has_more_than_one_atom?) | |
end | |
def domain_and_address_present? | |
email.domain && email.address == value | |
end | |
def domain_has_more_than_one_atom? | |
tree.domain.dot_atom_text.elements.length > 1 | |
end | |
def add_error | |
if message = options[:message] | |
record.errors[attribute] << message | |
else | |
record.errors.add(attribute, :invalid) | |
end | |
end | |
end |
require 'spec_helper' | |
describe Author do | |
def author(attributes = {}) | |
@author ||= Author.make(attributes) # assuming you're using Machinist | |
end | |
describe '#email' do | |
%w[[email protected] [email protected] [email protected] [email protected]].each do |valid_address| | |
context "when #{valid_address.inspect}" do | |
it 'has no errors on email' do | |
author(email: valid_address).valid? | |
author.should have(0).errors_on(:email) | |
end | |
end | |
end | |
%w[haxors @blah can@haz].each do |invalid_address| | |
context "when #{invalid_address.inspect}" do | |
it 'has one error on email' do | |
author(email: invalid_address).valid? | |
author.should have(1).error_on(:email) | |
end | |
end | |
end | |
end | |
end |
I posted this on the original rails-royce blog post as well:
This validator seems to allow multiple email addresses:
p = Person.new
p.name = “Test”
p.email = “[email protected], [email protected]”
p.valid? # => true
Is that intended?
I spoke too soon. I can't see why exactly but your refactored version catches my example where the original didn't.
(My fork of this gist just tests the above case and makes the spec shorter)
@JamesFerguson your example ought to be added to the unit test I think, and this ought to be turned into a gem so the unit tests can be run more easily. (Maybe with a script that builds an example rails/sqlite app.)
I have packaged this code up in to a gem and shared it on Github.
You can find it at http://github.com/evently/validate_as_email.
awesome!
I'm interested in helping you turn this into a gem next time I have free time.