123456789_123456789_123456789_123456789_123456789_

Module: ActiveModel::Attributes::Normalization

Relationships & Source Files
Namespace Children
Modules:
Classes:
Extension / Inclusion / Inheritance Descendants
Included In:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Defined in: activemodel/lib/active_model/attributes/normalization.rb

Class Method Summary

::ActiveSupport::Concern - Extended

class_methods

Define class methods from given block.

included

Evaluate given block in context of base class, so that you can write class macros here.

prepended

Evaluate given block in context of base class, so that you can write class macros here.

append_features, prepend_features

Instance Method Summary

DSL Calls

included

[ GitHub ]


8
9
10
11
12
13
14
15
# File 'activemodel/lib/active_model/attributes/normalization.rb', line 8

included do
  include ActiveModel::Dirty
  include ActiveModel::Validations::Callbacks

  class_attribute :normalized_attributes, default: Set.new

  before_validation :normalize_changed_in_place_attributes
end

Instance Method Details

#normalize_attribute(name)

Normalizes a specified attribute using its declared normalizations.

Examples

class User
  include ActiveModel::Attributes
  include ActiveModel::Attributes::Normalization

  attribute :email, :string

  normalizes :email, with: -> email { email.strip.downcase }
end

legacy_user = User.load_from_legacy_data(...)
legacy_user.email # => " CRUISE-CONTROL@EXAMPLE.COM\n"
legacy_user.normalize_attribute(:email)
legacy_user.email # => "cruise-control@example.com"

Behavior with Active Record

To prevent confusion, normalization will not be applied when the attribute is fetched from the database. This means that if a record was persisted before the normalization was declared, the record’s attribute will not be normalized until either it is assigned a new value, or it is explicitly migrated via #normalize_attribute.

Be aware that if your app was created before ::Rails 7.1, and your app marshals instances of the targeted model (for example, when caching), then you should set ActiveRecord.marshalling_format_version to 7.1 or higher via either config.load_defaults 7.1 or config.active_record.marshalling_format_version = 7.1. Otherwise, Marshal may attempt to serialize the normalization Proc and raise TypeError.

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"
[ GitHub ]

  
# File 'activemodel/lib/active_model/attributes/normalization.rb', line 70

def normalize_attribute(name)
  # Treat the value as a new, unnormalized value.
  send(:"#{name}=", send(name))
end

#normalize_changed_in_place_attributes (private)

[ GitHub ]

  
# File 'activemodel/lib/active_model/attributes/normalization.rb', line 140

def normalize_changed_in_place_attributes
  self.class.normalized_attributes.each do |name|
    normalize_attribute(name) if attribute_changed_in_place?(name)
  end
end