add validator for typoed emails
It happens quite often that people typo their email address (I blame phone keyboards for that). Catch common cases in a validator and tell the user that they have a typo in their email. Why yes, I did write the tests for this first, thanks for asking!
This commit is contained in:
parent
515e6d09ff
commit
29923fac84
|
@ -61,7 +61,7 @@ class User < ApplicationRecord
|
|||
screen_name.strip!
|
||||
end
|
||||
|
||||
validates :email, fake_email: true
|
||||
validates :email, fake_email: true, typoed_email: true
|
||||
validates :screen_name, presence: true, format: { with: SCREEN_NAME_REGEX }, uniqueness: { case_sensitive: false }, screen_name: true
|
||||
|
||||
mount_uploader :profile_picture, ProfilePictureUploader, mount_on: :profile_picture_file_name
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class TypoedEmailValidator < ActiveModel::EachValidator
|
||||
# this array contains "forbidden" email address endings
|
||||
INVALID_ENDINGS = [
|
||||
# without @:
|
||||
*%w[
|
||||
.con
|
||||
.coom
|
||||
],
|
||||
|
||||
# with @:
|
||||
*%w[
|
||||
fmail.com
|
||||
gemail.com
|
||||
gmail.co
|
||||
gmaile.com
|
||||
gmaill.com
|
||||
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 @
|
||||
return false unless value.include?('@')
|
||||
|
||||
# part after the @ needs to have at least one period
|
||||
return false if value.split('@', 2).last.count('.') == 0
|
||||
|
||||
# finally, common typos
|
||||
return false if INVALID_ENDINGS.any? { value.end_with?(_1) }
|
||||
|
||||
true
|
||||
end
|
||||
end
|
|
@ -33,6 +33,61 @@ RSpec.describe User, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'email validation' do
|
||||
subject do
|
||||
FactoryBot.build(:user, email: email).tap(&:validate).errors[:email]
|
||||
end
|
||||
|
||||
shared_examples_for 'valid email' do |example_email|
|
||||
context "when email is #{example_email}" do
|
||||
let(:email) { example_email }
|
||||
|
||||
it "does not have validation errors" do
|
||||
expect(subject).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'invalid email' do |example_email|
|
||||
context "when email is #{example_email}" do
|
||||
let(:email) { example_email }
|
||||
|
||||
it "has validation errors" do
|
||||
expect(subject).not_to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
include_examples 'valid email', 'ifyouusethismailyouarebanned@nilsding.org'
|
||||
include_examples 'valid email', 'fritz.fantom@gmail.com'
|
||||
include_examples 'valid email', 'fritz.fantom@columbiamail.co'
|
||||
include_examples 'valid email', 'fritz.fantom@protonmail.com'
|
||||
include_examples 'valid email', 'fritz.fantom@enterprise.k8s.420stripes.k8s.needs.more.k8s.jira.atlassian.k8s.eu-central-1.s3.amazonaws.com'
|
||||
include_examples 'invalid email', '@jack'
|
||||
|
||||
# examples from the real world:
|
||||
|
||||
# .con is not a valid TLD
|
||||
include_examples 'invalid email', 'fritz.fantom@gmail.con'
|
||||
include_examples 'invalid email', 'fritz.fantom@protonmail.con'
|
||||
# neither is .coom
|
||||
include_examples 'invalid email', 'fritz.fantom@gmail.coom'
|
||||
# common typos:
|
||||
include_examples 'invalid email', 'fritz.fantom@fmail.com'
|
||||
include_examples 'invalid email', 'fritz.fantom@gemail.com'
|
||||
include_examples 'invalid email', 'fritz.fantom@gmail.co'
|
||||
include_examples 'invalid email', 'fritz.fantom@gmailcom'
|
||||
include_examples 'invalid email', 'fritz.fantom@gmaile.com'
|
||||
include_examples 'invalid email', 'fritz.fantom@gmaill.com'
|
||||
include_examples 'invalid email', 'fritz.fantom@hotmailcom'
|
||||
include_examples 'invalid email', 'fritz.fantom@icluod.com'
|
||||
# no TLD
|
||||
include_examples 'invalid email', 'fritz.fantom@gmail'
|
||||
include_examples 'invalid email', 'fritz.fantom@protonmail'
|
||||
# not registered as of 2022-01-11
|
||||
include_examples 'invalid email', 'fritz.fantom@proton.mail'
|
||||
end
|
||||
|
||||
# -- User::TimelineMethods --
|
||||
|
||||
shared_examples_for 'result is blank' do
|
||||
|
|
Loading…
Reference in New Issue