2022-01-11 09:37:07 -08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
class TypoedEmailValidator < ActiveModel::EachValidator
|
|
|
|
# this array contains "forbidden" email address endings
|
|
|
|
INVALID_ENDINGS = [
|
|
|
|
# without @:
|
2022-01-17 10:23:39 -08:00
|
|
|
".con",
|
|
|
|
".coom",
|
2022-01-11 09:37:07 -08:00
|
|
|
|
|
|
|
# with @:
|
|
|
|
*%w[
|
|
|
|
fmail.com
|
|
|
|
gemail.com
|
|
|
|
gmail.co
|
|
|
|
gmaile.com
|
|
|
|
gmaill.com
|
2022-01-17 10:22:34 -08:00
|
|
|
gmali.com
|
2022-01-11 09:37:07 -08:00
|
|
|
icluod.com
|
|
|
|
proton.mail
|
|
|
|
].map { "@#{_1}" }
|
|
|
|
].freeze
|
|
|
|
|
|
|
|
def validate_each(record, attribute, value)
|
|
|
|
return if valid?(value)
|
|
|
|
|
|
|
|
record.errors[attribute] << "contains a typo"
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def valid?(value)
|
|
|
|
# needs an @
|
2022-01-17 10:23:39 -08:00
|
|
|
return false unless value.include?("@")
|
2022-01-11 09:37:07 -08:00
|
|
|
|
|
|
|
# part after the @ needs to have at least one period
|
2022-01-17 10:23:39 -08:00
|
|
|
return false if value.split("@", 2).last.count(".").zero?
|
2022-01-11 09:37:07 -08:00
|
|
|
|
|
|
|
# finally, common typos
|
|
|
|
return false if INVALID_ENDINGS.any? { value.end_with?(_1) }
|
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end
|