バリデーションとは?
バリデーションとは、Active Recordモデルに対して、データの検証を行う機能です。
データベースに保存する前にユーザーが入力したデータを検証し、不正な値がある場合にはエラーメッセージを表示します。
Active Recordモデルでバリデーションを定義するにはvalidates
メソッドを使用します。
このメソッドは、モデルの属性に対して検証ルールを設定するためのオプションを受け取ります。
基本的な書き方
バリデーションはvalidates
にカラム名と検証ルールを指定して記述します。
基本的な書き方を以下に示します。
validates :カラム名, 検証ルール
バリデーションの種類
Railsで利用可能な主要なバリデーションの種類を一覧を示します。
種類 | 内容 |
---|---|
presence | 値が存在しているか検証する。空文字やnil の場合にエラーとなる。 |
absence | 値が存在しないことを検証する。存在している場合にエラーとなる。 |
uniqueness | 一意性の検証をする。重複している値がある場合にエラーとなる。 |
numericality | 数値を検証する。指定された条件に合わない場合にエラーとなる。 |
length | 文字列の長を検証する。指定された条件に合わない場合にエラーとなる。 |
format | フォーマットを検証する。正規表現を指定して、指定されたパターンに合わない場合にエラーとなる。 |
inclusion | 値が含まれているか検証する。指定された値が含まれていない場合にエラーとなる。 |
exclusion | 値が含まれていないか検証する。指定された値が含まれている場合にエラーとなる。 |
confirmation | 2つの値が完全に一致しているか検証する。パスワードの確認などに使用する。 |
acceptance | チェックボックスにチェックされているか検証する。チェックボックスがチェックされていない場合にエラーとなる。 |
validates_associated | 関連先のバリデーションを検証する。関連先のバリデーションに問題がある場合にエラーとなる。 |
validates_with | 独自で作成したカスタムバリデーションを使用する。 |
validates_each | 1つのブロックに対して属性を検証する。 |
presenceの使い方
presence
バリデーションは指定された値が存在することを検証します。
指定された属性がnilまたは空の場合にエラーを発生させます。
例えば、Userモデルにname属性がある場合、以下のようにバリデーションを追加します。
class User < ApplicationRecord
validates :name, presence: true
end
上記の例ではUserモデルのname属性にpresence: true
を追加することで、name属性が存在することを検証しています。
つまり、name属性は空にしてはいけません。
name属性が空の場合バリデーションエラーが発生しデータベースには保存されません。
また、presence
バリデーションは外部キーの存在を検証するときにも使用できます。
以下はPostモデルでuser_id属性にpresence
バリデーションを使用する例です。
class Post < ApplicationRecord
belongs_to :user
validates :user_id, presence: true
end
上記の例ではPostモデルがUserモデルに属しており、user_idカラムにpresence
バリデーションが設定されています。
これによりPostモデルのレコードが作成される前にuser_idカラムが空でないことを検証することができます。
Postモデルのレコードを作成する前に関連するUserモデルのレコードが作成されていることを検証することができます。
これらの例からも分かるようにpresence
バリデーションは、モデルに存在する属性や関連の存在を確認するために非常に便利なバリデーションです。
必須フィールドや外部キーの存在を検証するときはpresence
バリデーションを積極的に使用すると安全性を高めることができます。
absenceの使い方
absence
バリデーションは特定の値が存在しないことを検証します。presence
バリデーションとは対照的に値が存在しないときにバリデーションを通過します。
以下はUserモデルでname属性が存在しないことを検証する例です。
class User < ApplicationRecord
validates :name, absence: true
end
name属性に何らかの値が設定されている場合はバリデーションエラーが発生します。
name属性が空でなければバリデーションを通過しません。
uniquenessの使い方
uniqueness
バリデーションは、値が一意であることを検証します。
同じ値を持つレコードを複数存在させたくないときなどによく使われます。
以下はUserモデルでemail属性が一意であることを検証する例です。
class User < ApplicationRecord
validates :email, uniqueness: true
end
既にemailカラムに同じ値が存在しているときはバリデーションエラーが発生します。
また、scope
オプションを使用して、一意性を検証する範囲を限定する事もできます。
例えば、同じteam_idの値を持つレコードの範囲で、usernameの値が一意であることを検証する場合は以下のようになります。
class User < ApplicationRecord
validates :username, uniqueness: { scope: :team_id }
end
上記の例ではusernameカラムとteam_idカラムの値の組み合わせが一意であることを検証しています。
これによりusernameの値が同じteam_idカラムを持つ複数のレコードに存在しないことを検証できます。
numericalityの使い方
numericality
バリデーションは、値が数値であることを検証します。
属性の値が整数または浮動小数点数であることを検証できます。
以下は、Productモデルでprice属性が数値であることを検証する例です。
class Product < ApplicationRecord
validates :price, numericality: true
end
もし、priceカラムの値が数値でない場合はバリデーションエラーが発生します。
また、以下オプションで値に制約を付けることができます。
オプション | 説明 |
---|---|
only_integer | true の場合は整数でなければならない。 |
greater_than | 指定の値よりも大きくなければならない。 |
greater_than_or_equal_to | 指定の値と等しいか、それよりも大きくなければならない。 |
equal_to | 指定の値と等しくなければならない。 |
less_than | 指定の値よりも小さくなければならない。 |
less_than_or_equal_to | 指定の値と等しいか、それよりも小さくなければならない。 |
other_than | 指定の値以外の値でなければならない。 |
in | 指定された範囲に値が含まれていなければならない。 |
odd | true の場合は奇数でなければならない。 |
even | true の場合は偶数でなければならない。 |
以下はProductモデルでprice属性が10以上であることを検証する例です。
class Product < ApplicationRecord
validates :price, numericality: { greater_than_or_equal_to: 10 }
end
また、only_integer
オプションを使用して、属性の値が整数であることを検証する例です。
class Product < ApplicationRecord
validates :quantity, numericality: { only_integer: true }
end
これらのオプションを組み合わせて、より複雑な数値のバリデーションを行うこともできます。
numericality
バリデーションはデータの正確性を確保する上で非常に有用ですが、値が文字列である場合は適用されませんので注意しましょう。
lengthの使い方
length
バリデーションは値が指定された文字数の範囲内にあることを検証します。
値が文字列または配列である場合は値の長さが指定された範囲内であることを検証します。
また値が数値である場合、数値の桁数が指定された範囲内であることを検証します。
属性がハッシュ(Hash)である場合はハッシュのサイズが指定された範囲内であることを検証します。
以下のオプションで長さを制限することができます。
オプション | 説明 |
---|---|
minimum | 指定の値より小さな値にはできない。 |
maximum | 指定の値より大きな値にはできない。 |
in | 指定された範囲内の値でなければならない。 |
is | 指定の値と等しい値でなければならない。 |
例えば、Userモデルでnameカラムが2文字以上30文字以下であることを検証する場合、以下のようなバリデーションを定義できます。
class User < ApplicationRecord
validates :name, length: { minimum: 2, maximum: 30 }
end
また、length
バリデーションではin
オプションを使用して、カラムの値が指定された範囲内にあることを検証することもできます。
例えば、以下のようにdescriptionカラムが100文字以上200文字以下であることを検証することができます。
class Product < ApplicationRecord
validates :description, length: { in: 100..200 }
end
さらににis
オプションを使用して、値の長さが指定された値に等しいことを検証することもできます。
例えば、以下のようにzipcodeカラムが7文字であることを検証することができます。
class Address < ApplicationRecord
validates :zipcode, length: { is: 7 }
end
formatの使い方
format
バリデーションは、値が指定された正規表現と一致するかどうかを検証します。
例えば、メールアドレスの形式が正しいかどうかを検証する場合は、次のように書くことができます。
class User < ApplicationRecord
validates :email, format: { with:/\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i }
end
without
オプションを使うと、指定された形式にマッチしない正規表現を検証することもできます。
inclusionの使い方
inclusion
バリデーションは指定された値が含まれているかどうかを検証するバリデーションです。
例えば、性別を「男性」「女性」「その他」のいずれかに限定したい場合に使用できます。
以下は、性別を「男性」「女性」「その他」のいずれかに限定する例です。
class User < ApplicationRecord
validates :gender, inclusion: { in: ['male', 'female', other'] }
end
値が配列に含まれている場合はバリデーションを通過し、含まれていない場合はバリデーションエラーが発生します。
exclusionの使い方
exclusion
バリデーションは、指定された値が含まれていないかどうかを検証するバリデーションです。
例えば、パスワードに特定の文字列を含めたくない場合に使用できます。
以下は、パスワードに「password」と「admin」といった文字列を含めさせない例です。
class User < ApplicationRecord
validates :password, exclusion: { in: ['password', 'admin'] }
end
値が含まれている場合はバリデーションエラーが発生し、含まれていない場合はバリデーションを通過します。
入力値に特定のキーワードが含まれないようにする場合や、特定の値を除外したい場合など、exclusion
バリデーションは値が特定の値や文字列を含まないようにする場合に便利です。
confirmationの使い方
confirmation
バリデーションは、入力された値が同じかどうかを検証するバリデーションです。
通常はパスワードなどのフィールドに使用されます。
例えば、ユーザーがパスワードを入力し、同じパスワードを再度入力する必要がある場合に使用します。
class User < ApplicationRecord
validates :password, confirmation: true
end
この例では、Userモデルのpasswordカラムにに対してconfirmationバリデーションを追加しています。
確認用のフィールドの名前は、確認したい属性名に「_confirmation」を追加したものになります。
<%= text_field :user, :password %>
<%= text_field :user, :password_confirmation %>
またcase_sensitive
オプションを用いて、大文字小文字を区別するか制限をすることができます。
デフォルトでは、このオプションはtrue
になります。
class User < ApplicationRecord
validates :password, confirmation: { case_sensitive: false }
end
confirmation
バリデーションは、入力された値が一致するかどうかを確認するため、メールアドレスの確認などパスワード以外の任意の値に対しても使用することができます。
acceptanceの使い方
acceptance
バリデーションは、フォームなどでチェックボックスの入力を検証する際に使用されるバリデーションです。
このバリデーションを使用することで、チェックボックスがチェックされていることを検証できます。
利用規約の同意など何らかの文書に目を通したことを確認させる場合によく使われます。
acceptance
バリデーションを使用するには、モデルで以下のように定義します。
class User < ApplicationRecord
validates :terms_of_service, acceptance: true
end
またaccept
オプションを付けることで「同意済み(accepted)」とみなす値を指定できます
デフォルトは['1', true]
となっています。
変更は以下のように簡単にできます。
class User < ApplicationRecord
validates :terms_of_service, acceptance: { accept: 'yes' }
validates :eula, acceptance: { accept: ['TRUE', 'accepted'] }
end
validates_associatedの使い方
alidates_associated
バリデーションは、関連するモデルを検証するバリデーションです。
モデルAとモデルBが関連している場合、モデルAの保存時に自動的にモデルBのバリデーションが実行されます。
例えば、投稿を行うアプリケーションでは、投稿に紐づくコメントがあります。
投稿を保存する際に、その投稿に紐づくコメントのバリデーションも同時に行いたいときvalidates_associated
バリデーションを使用できます。
具体的には、モデルで以下のように定義します。
class Post < ApplicationRecord
has_many :comments
validates_associated :comments
end
これにより、投稿を保存する際に自動的にコメントのバリデーションを実行させることができます。
validates_withの使い方
validates_with
メソッドは、ActiveModelのバリデーション機能を使って、独自のバリデーションを定義するときに使用します。
これにより、任意のカスタムバリデータを作成し、そのバリデータをモデルに適用することができます。
以下は、validates_with
を使用して独自のカスタムバリデーションを作成する手順です。
まず、バリデーションを実行するためのカスタムバリデータクラスを作成する必要があります。 このクラスは、ActiveModel::Validatorを継承する必要があります。
class MyValidator < ActiveModel::Validator
def validate(record)
# validation logic here
end
end
次に、validates_with
メソッドを使用して、先程作成したバリデータクラスをモデルに適用します。
class MyModel < ActiveRecord::Base
validates_with MyValidator
end
最後に、カスタムバリデーションクラスでvalidate
メソッドを実装して、バリデーションロジックを定義します。validate
メソッドは、引数としてモデルのインスタンスを受け取ります。
class MyValidator < ActiveModel::Validator
def validate(record)
if record.some_attribute == "invalid"
record.errors.add :some_attribute, "is invalid"
end
end
end
上記の例では、モデルのsome_attribute
が「invalid」である場合にエラーを追加しています。
record.errors
オブジェクトは、ActiveModel::Errorsオブジェクトで、モデルのエラーメッセージを格納するために使用されます。
validates_eachの使い方
validates_each
メソッドは、ActiveModelのバリデーション機能を使って、1つのブロックに対して独自のバリデーションを定義することができます。
定義済みのバリデーション関数はないため、ブロックを使うバリデーションを自分で作成します。
以下は、validates_each
を使用して独自のカスタムバリデーションを作成する例です。
class MyModel < ActiveRecord::Base
validates_each :attribute_name do |record, attr, value|
unless value.is_valid?
record.errors.add(attr, "is not valid")
end
end
end
このブロックは、レコード(record)と属性の名前(attr)、そして属性の値(value)を受け取ります。
ブロック内で、属性の値をチェックし、エラーがある場合はエラーメッセージを追加します。
上記の例では、属性attribute_name
の値がis_valid?
でない場合、エラーメッセージが追加されます。record.errors
オブジェクトは、ActiveModel::Errorsオブジェクトで、モデルのエラーメッセージを格納するために使用されます。
最後に、モデルをバリデーションする方法です。
通常のバリデーションのように、valid?
メソッドを呼び出します。
model = MyModel.new(attribute_name: 'invalid value')
model.valid? # => false
model.errors[:attribute_name] # => ['is not valid']
上記の例では、attribute_name
の値が”invalid value”であるため、valid?
メソッドはfalseを返し、エラーメッセージがmodel.errors
オブジェクトに追加されます。
共通のバリデーションオプション
allow_nilの使い方
allow_nil
オプションは、バリデーションを行う際に、対象となる属性の値がnil
であってもバリデーションを通過することを許可するためのオプションです。
allow_nil
を使用すると、presenceバリデーションなど、属性が空であることを検証するバリデーションでnil
の値が許容されるように変更できます。
例えば、以下のようなコードを書くことができます。
class User < ApplicationRecord
validates :name, presence: true, allow_nil: true
end
このコードでは、Userモデルのname属性に対して、presenceバリデーションを適用し、allow_nil
オプションを追加しています。
そのため、このバリデーションではnameカラムの値がnil
である場合はバリデーションを通過します。
allow_nil
オプションは、バリデーションが必要ない場合に便利です。
例えば、オプションの属性が設定されていない場合にはバリデーションを実行せず、属性が設定されている場合には属性が適切な値であるかどうかを検証するというような使い方ができます。
allow_blankの使い方
allow_blank
オプションは、バリデーションを行う際に、対象となる属性の値がnil
や空白文字列(""
)など空の状態のとき(値がblank?
に該当するとき)にバリデーションを通過することを許可するためのオプションです。
allow_blank
を使用すると、presenceバリデーションなど属性が空であることを検証するバリデーションで空白文字列が許容されるように変更できます。
例えば、以下のようなコードを書くことができます。
class User < ApplicationRecord
validates :name, presence: true, allow_blank: true
end
このコードでは、Userモデルのname属性に対して、presenceバリデーションを適用し、allow_blank
オプションを追加しています。
そのため、nameカラムの値が空白文字列である場合もバリデーションを通過します。
messageの使い方
message
オプションは、バリデーションが失敗した場合に表示するエラーメッセージを指定するためのオプションです。
例えば、以下のようなバリデーションコードがあるとします。
class User < ApplicationRecord
validates :name, presence: true
end
この場合、name
属性が空である場合にバリデーションが失敗し、「Name can’t be blank」というエラーメッセージが自動的に生成されます。
こちらのデフォルトのエラーメッセージの内容を変更したいときはmessage
オプションを使用することで、独自のエラーメッセージを指定できます。
例えば、以下のように書くことができます。
class User < ApplicationRecord
validates :name, presence: { message: "Please enter your name." }
end
上記のコードにすることで、nameカラムが空でバリデーションが失敗した場合に、「Please enter your name.」という独自のエラーメッセージが表示されます。
message
オプションは、バリデーションが失敗した場合にユーザーに対して適切な情報を提供するための重要な役割をします。
複数のバリデーションを適用する場合には、各バリデーションごとに異なるエラーメッセージを指定することができるため、エラーの原因が明確になります。
onの使い方
on
オプションは、どのタイミングでバリデーションを実行するかを指定するためのオプションです。
デフォルトでは、Railsはオブジェクトが保存される前にすべてのバリデーションを実行します。
しかし、on
オプションを使用すると、特定のタイミングでのみバリデーションを実行することができます。
on
オプションで指定できる値は以下の通りです。
メソッド | 説明 |
---|---|
create | 新規作成時のみバリデーションを実行する |
update | 更新時のみバリデーションを実行する |
save | 保存時にバリデーションを実行する |
validation | バリデーション時に常に実行する(デフォルト) |
例えば、以下のようなコードを書くことができます。
class User < ApplicationRecord
validates :email, presence: true, on: :create
end
このコードでは、email
属性に対してpresence
バリデーションを適用しています。
また、on: :create
オプションを指定することで、新規作成時のみバリデーションを実行するように設定しています。
これにより、既存のレコードを更新する場合にはemail
属性が空であっても保存ができるようになります。
on
オプションを使用することで、必要なタイミングでバリデーションを実行することができ、より柔軟なバリデーションの設定が可能になります。
条件付きバリデーション
条件付きバリデーションとは、ある特定の条件を満たしたときに実行したいバリデーションのことです。
標準のバリデーションだけでは対応できない場合に使用されます。
例えば、あるカラムが特定の値を持っているときに、そのカラムに対するバリデーションを実行する、といった使い方ができます。
条件付きバリデーションを実装する方法は複数ありますが、一般的には、if
やunless
オプションを使用する方法が使われます。
これらのオプションを使用することで、特定の条件を指定し、その条件が満たされた場合にバリデーションを実行するように設定することができます。
以下は、if
オプションを使用した例です。
class User < ApplicationRecord
validates :email, presence: true, if: :email_required?
def email_required?
true
end
end
上記の例では、emailカラムに対して、presenceバリデーションが設定されていますが、if
オプションでemail_required?
メソッドを指定しています。
このメソッドがtrueを返す場合には、presenceバリデーションが実行されます。
class User < ApplicationRecord
with_options if: :is_admin? do |admin|
admin.validates :email, presence: true
admin.validates :password, presence: true
end
def is_admin?
true
end
end
上記の例では、is_admin?
メソッドがtrueを返す場合には、emailカラムとpasswordカラムに対してpresenceバリデーションが実行されます。
以上のように、if
やunless
オプションを使用することで、条件付きバリデーションを簡単に実装することができます