Rails 7.1: ActiveRecord::Base
にnormalizes
が追加された(翻訳)
Rails 7.1で、Active Recordの属性値の正規化(normalization)を宣言するメソッドが新たに追加されました。これは、ユーザー入力のサニタイズ、書式の統一、外部由来のデータのクリーンアップで特に有用です。
Rails 7.1より前は、以下のようにbefore_save
コールバックで属性を正規化できます。
model User < ApplicationRecord
before_save :downcase_email, if :email_present?
private
def email_present?
email.present?
end
def downcase_email
email.downcase!
end
end
Rails 7.1では、同じコードを以下のような形にリファクタリングできます。
model User < ApplicationRecord
normalizes :email, with: -> email { email.downcase }
end
この正規化は、属性への代入や属性の更新時に適用され、正規化済みの値はデータベースで永続化されます。この正規化は、finderメソッドで対応するキーワード引数にも適用されます。これにより、作成されたレコードについて、正規化されていない値を用いて後からクエリをかけられるようになります。
デフォルトでは、nil
値に対して正規化は適用されません。nil
値を正規化するには、以下のようにapply_to_nil:
オプションでnil
の正規化を有効にできます。
model User < ApplicationRecord
normalizes :user_name, with:
-> user_name { user_name.parameterize.underscore }
normalizes :email, with: -> { _1.strip.downcase }
normalizes :profile_image, with:
-> profile_image {
profile_image.present? ? URI.parse(profile_image).to_s :
"https://source.boringavatars.com/beam" },
apply_to_nil: true
end
# rails console
>> User.create!(user_name: "Eve Smith", email: "eveSmith@EXAMPLE.com")
#<User:0x000000010b757090 id: 1, user_name: "eve_smith", profile_image:"https://source.boringavatars.com/beam", email: "evesmith@example.com", created_at: Wed, 03 May 2023 07:49:20.067765000 UTC +00:00, updated_at: Wed, 03 May 2023 07:49:20.067765000 UTC +00:00>
>> user = User.find_by!(email: "EVESMITH@example.COM")
>> user.email # => "evesmith@example.com"
>> User.exists?(email: "EveSmith@Example.COM") # => true
ここでユーザーのメールアドレスが、正規化ステートメントがモデルに追加される前にデータベースに保存されていた場合、そのメールアドレスは正規化済みの形では取得されません。
その理由は、データベース内でメールの大文字小文字が混在している、つまり正規化されずに保存されているためです。そのようなレガシーデータがある場合は、Normalization#normalize_attribute
メソッドを明示的に利用することで正規化できます。
# rails console
>> legacy_user = User.find(1)
>> legacy_user.email # => "adamSmith@EXAMPLE.com"
>> legacy_user.normalize_attribute(:email)
>> legacy_user.email # => "adamsmith@example.com"
>> legacy_user.save
詳しくは#43945をご覧ください。
概要
元サイトの許諾を得て翻訳・公開いたします。