ruby 22 lines · 7 steps

Writing a custom email validator in Rails

A reusable ActiveModel validator that checks email format and enforces RFC length and dot rules.

Explained by highlit
1class EmailValidator < ActiveModel::EachValidator
2 EMAIL_FORMAT = /\A[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\z/i
3 
4 def validate_each(record, attribute, value)
5 return if value.blank?
6 
7 normalized = value.to_s.strip.downcase
8 
9 unless normalized.match?(EMAIL_FORMAT)
10 record.errors.add(attribute, options[:message] || :invalid)
11 return
12 end
13 
14 local, domain = normalized.split("@", 2)
15 
16 if local.length > 64 || normalized.length > 254
17 record.errors.add(attribute, :too_long)
18 elsif domain.include?("..") || local.start_with?(".") || local.end_with?(".")
19 record.errors.add(attribute, :invalid)
20 end
21 end
22end
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Subclassing EachValidator lets you drop custom rules into any model with a one-line declaration.
  2. 2Normalizing input before validating avoids false failures from casing and stray whitespace.
  3. 3Regex handles shape while explicit length and dot checks catch cases a pattern misses.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Writing a custom email validator in Rails — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code