Skip to content

Validators ​

Validators available to any Active Record or Active Model class of the app (User, a sign-up, a contact or newsletter form…): Trek's own, and those of the gems Trek depends on, which it loads.

ValidatorKeyFrom
Disposable email addressesnot_disposableTrek
Email formatemailemail_validator
Email checks"valid_email_2/email"valid_email2
Phone numbersphonePhonelib
Uniqueness of a translated attributeuniquenessMobility

Disposable email addresses ​

NotDisposableValidator refuses an email address from a throwaway email provider (mailinator.com, yopmail.com…), or a subdomain of one, whatever its case:

ruby
class Contact < ApplicationRecord
  validates :email, presence: true, email: { mode: :strict }, not_disposable: true
end

It is opt-in: Trek doesn't add it to User, whose accounts admins create. A blank address is left to the presence validation.

The error is :disposable, « is a disposable email address, use a permanent one » (« est une adresse e-mail jetable, utilisez-en une permanente »). Change it in the app's locales (errors.messages.disposable), or per model:

ruby
validates :email, not_disposable: { message: "must be your work address" }

The domains come from the valid_email2 gem, whose maintainers keep the list up to date: updating the gem updates the list, with no data to refresh in the app. Only the list is checked, without looking up the domain's mail servers. To let a domain through, list it in config/allow_listed_email_domains.yml:

yaml
- legit-provider.example

The list (about 180,000 domains) is loaded on the first check, as a single string of 2.6 MB searched by bisection, rather than valid_email2's own Set of about 35 MB: about 5 µs per address.

Email format ​

EmailValidator checks an address's shape, without any network lookup:

ruby
validates :email, email: { mode: :strict }
OptionDefault
mode:loose:loose only asks for something on each side of an @; :strict refuses consecutive or leading/trailing dots and asks for a domain with a TLD; :rfc follows RFC 5322
require_fqdn— (true in :strict mode)a domain with a TLD
domain—only this domain, e.g. domain: "example.com"
allow_nilfalse

User uses :strict mode.

Email checks ​

valid_email2's validator checks an address's shape too, and optionally more: its domain's mail servers (mx: true, strict_mx: true), a deny list (deny_list: true, from config/deny_listed_email_domains.yml), or refusing +tag addresses (disallow_subaddressing: true). See its options.

ruby
validates :email, "valid_email_2/email": { mx: true }
  • mx and strict_mx look the domain up in the DNS on every validation, which can take up to dns_timeout (5 seconds) and fails offline, in specs too.
  • For disposable addresses, use not_disposable rather than its disposable options: they load its Set of 180,000 domains, which grows each process by about 35 MB.

Phone numbers ​

PhoneValidator checks a phone number with Phonelib, against Phonelib.default_country when the number has no country code:

ruby
validates :phone, phone: { possible: true, allow_blank: true }
Option
possibletrue to only ask whether the digits could form a number for the country; otherwise they must fall in a range actually assigned (see Strictness)
typese.g. :mobile, [:mobile, :fixed]
countriese.g. [:fr, :be]
allow_blanka blank value fails otherwise

Trek::Phonable adds it for you, with the number's normalization and formatting.

Uniqueness of a translated attribute ​

On a model with translated attributes, Mobility replaces uniqueness, so it works on them too, in the current locale: a title taken in English is still free in French.

ruby
class Fragment < ApplicationRecord
  include Trek::Translatable
  translate_attributes :title, :content
  validates :title, uniqueness: true
end

Released under the MIT License.