Before Rails 7.1
Once upon a time, way long before the Rails 7.1 era, a smart Rails developer (like yourself) needed to ensure user email addresses were properly normalized (sanitized and formatted correctly). Back then, they used clever techniques such as callbacks like before_save and before_validation, attribute setters, or even the normalize gem to get the job done. Here are some of those old tricks and tips on how they used to do it.
# normalize with before_save callback class User < ApplicationRecord before_save :sanitize_email private def sanitize_email self.email = email.strip.downcase end end # normalize with before_validation callback class User < ApplicationRecord before_validation :sanitize_email private def sanitize_email self.email = email.strip.downcase end end # override the setter from ActiveRecord class User < ApplicationRecord def email=(value) super(value.strip.downcase) end end # Don't like callbacks? Use the normalize gem in `app/normalizers` class EmailNormalizer def self.call(email) email.strip.downcase end end class User < ApplicationRecord normalize :email, with: EmailNormalizer end
After Rails 7.1
As time passed, the Rails community reached the Rails 7.1 era. A group of those smart Rails developers (maybe it's you) gathered around the Rails core team and agreed on a better way to normalize attributes. They came up with a nifty idea.
Imagine having a ClassMethod `normalizes` that comes with a set of rules, such as converting all email addresses to lowercase, removing leading/trailing whitespace, or enforcing a specific format before they are saved to the database. This "Normalization" class reduces data redundancy and minimizes inconsistencies. Also, it organizes data in a structured and consistent way, making it easier to query, update, and maintain.
The Rails core team wanted to make it easy for today's and future Rails developers by providing a simple API for model attributes. All developers need to do is pass the attribute's name. Here is how they demonstrated their solution. Pow 💥
Imagine having a ClassMethod `normalizes` that comes with a set of rules, such as converting all email addresses to lowercase, removing leading/trailing whitespace, or enforcing a specific format before they are saved to the database. This "Normalization" class reduces data redundancy and minimizes inconsistencies. Also, it organizes data in a structured and consistent way, making it easier to query, update, and maintain.
The Rails core team wanted to make it easy for today's and future Rails developers by providing a simple API for model attributes. All developers need to do is pass the attribute's name. Here is how they demonstrated their solution. Pow 💥
class User < ActiveRecord::Base normalizes :email, with: -> email { email.strip.downcase } normalizes :phone, with: -> phone { phone.delete("^0-9").delete_prefix("1") } end user = User.create(email: " CRUISE-CONTROL@EXAMPLE.COM\n") user.email # => "cruise-control@example.com" user = User.find_by(email: "\tCRUISE-CONTROL@EXAMPLE.COM ") user.email # => "cruise-control@example.com" user.email_before_type_cast # => "cruise-control@example.com" User.where(email: "\tCRUISE-CONTROL@EXAMPLE.COM ").count # => 1 User.where(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]).count # => 0 User.exists?(email: "\tCRUISE-CONTROL@EXAMPLE.COM ") # => true User.exists?(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]) # => false User.normalize_value_for(:phone, "+1 (555) 867-5309") # => "5558675309"
~~~~~
Coming to RailsWorld?
Coming to RailsWorld?
Check out my series, Ahmed’s Unofficial RailsWorld Guide to Toronto! This first-of-its-kind guide is perfect for RailsWorld attendees. I write about the history of the amazing venue, Evergreen Brickworks, take you on a ride from the airport to the city, hotels and around, and explore Toronto's best spots to eat, visit, and have fun. Whether you're attending the conference or just visiting the city, you'll find something valuable.
Yours,
Ahmed Nadar