Exploring ActiveRecord::Base::normalizes in Rails 7.1
Occasionally, there’s a need to standardize data before it’s stored in a database. For instance, you might want to convert email addresses to lowercase, eliminate leading and trailing spaces, and more. With the introduction of Rails 7.1, the new ActiveRecord::Base::normalizes API comes into play. This feature empowers you to normalize attribute values to a uniform format before they’re persisted in the database. By doing so, you enhance the integrity and consistency of your data and simplify the process of querying records based on attribute values
Prior to Rails 7.1, attribute normalization could be achieved by utilizing the before_save callback.
class User < ApplicationRecord
before_save :normalize_email
private
def normalize_email
self.email = email.strip.downcase if email.present?
end
end
Rails 7.1 onwards
class User < ActiveRecord::Base
normalizes :email, with: -> email { email.downcase.strip }
end
By default, the normalization will not be applied to nil values. This behavior can be modified using the apply_to_nil option, which is set to false by default.
class User < ActiveRecord::Base
normalizes :email, with: -> email { email&.downcase&.titleize || 'example@yourdomain.com' }, apply_to_nil: true
end
You can also utilize the normalizes method to apply normalization to multiple attributes simultaneously.
class User < ActiveRecord::Base
normalizes :email, :first_name, :last_name, :title, with: -> attribute { attribute.strip }
end
How can you apply normalization to pre-existing records?
Normalization takes effect when an attribute is assigned or updated. This implies that if a record was saved before the normalization rule was established, the attribute won’t be normalized until it receives a new value. To address this, you can explicitly perform migration through Normalization#normalize_attribute.
class User < ActiveRecord::Base
normalizes :email, with: ->(email) { email&.downcase&.strip }
end
User.find_each do |user|
# user.email # => "\n\nexample@DOMAIN.COM\n"
user.normalize_attribute(:email)
# user.email # => "example@domain.com"
user.save
end
Note: The normalization can be applied multiple times and is designed to be idempotent. This means that applying the normalization repeatedly will yield the same result as applying it just once.
Please review this pull request for more details.
Subscribe to my newsletter
Read articles from Arish Khan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Arish Khan
Arish Khan
Ruby On Rails/React.JS Developer