ruby 33 lines · 6 steps

Country-aware phone validation in Rails

A Contact model normalizes phone input, then validates it against per-country regex rules with tailored error messages.

Explained by highlit
1class Contact < ApplicationRecord
2 PHONE_FORMATS = {
3 "US" => /\A\+1\d{10}\z/,
4 "GB" => /\A\+44\d{10}\z/,
5 "DE" => /\A\+49\d{10,11}\z/,
6 "IN" => /\A\+91\d{10}\z/,
7 "BR" => /\A\+55\d{10,11}\z/
8 }.freeze
9 
10 before_validation :normalize_phone
11 
12 validates_each :phone do |record, attr, value|
13 country = record.country_code.to_s.upcase
14 format = PHONE_FORMATS[country]
15 
16 if value.blank?
17 record.errors.add(attr, :blank)
18 elsif format.nil?
19 record.errors.add(attr, :unsupported_country, country: country)
20 elsif !value.match?(format)
21 record.errors.add(attr, :invalid_phone, country: country)
22 end
23 end
24 
25 private
26 
27 def normalize_phone
28 return if phone.blank?
29 
30 digits = phone.gsub(/[\s().-]/, "")
31 self.phone = digits.start_with?("+") ? digits : "+#{digits}"
32 end
33end
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Normalizing input in a before_validation callback lets validation logic assume clean, canonical data.
  2. 2A lookup table of regexes keyed by identifier keeps per-case rules declarative and easy to extend.
  3. 3Distinct error keys let each failure mode produce its own translatable, context-rich message.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Country-aware phone validation in Rails — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code