Activeレコードの検証
このガイドでは、Active Recordの検証機能を使用してデータベースに入れる前に、 オブジェクトの状態を検証する方法について説明していきます。
このガイドを読むことで、次の事が学べるはずです。
- 組み込みのActive Record検証ヘルパーの使い方
- 開発者定義の検証メソッドの作成方法
- 検証プロセスにより、どのようにメッセージが生成されるか
1. 検証の概要
ここで、非常にシンプルな検証の例を示します。
class Person < ActiveRecord::Base
validates :name, presence: true
end
Person.create(name: "John Doe").valid? # => true
Person.create(name: nil).valid? # => false
ご覧の通り、検証はname属性の無いPersonが不正であることを知らせてくれます。 この例の2つ目のPersonは、データベースに保存されません。
更に詳細について学ぶ前に、検証をアプリケーションに適用させることについての全体像について話をしましょう。
1.1 なぜ、検証するのか?
2. 検証ヘルパー
Active Recordは、開発者が定義したクラス内で直接使用出来る多くの定義済み検証ヘルパーを提供してくれます。
これらのヘルパーは共通の検証ルールを提供します。
検証が失敗した際は、エラーメッセージがオブジェクトのerrors
コレクションに追加され、
このメッセージは検証された属性と関連付けられています。
各ヘルパーには、属性名を好きなだけ指定することができ、 1行で同じ種類の検証を複数の属性に追加することが可能です。
全ての検証ヘルパーは、実行されるべきタイミングを決める:on
と、
検証が失敗した際にerrorsコレクションに追加すべきメッセージを決める:message
オプションを受け入れます。
:on
オプションは、:save
(デフォルト)、:create
、:update
のうちの1つを指定することが出来ます。
検証ヘルパーのそれぞれに対して、デフォルトのエラーメッセージがあり、これらのメッセージは:message
オプションが指定されなかった際に使用されます。
それでは、利用可能な各検証ヘルパーについて見て行きましょう。
2.1 acceptance
このメソッドは、フォームが送信された際にユーザーがチェックボックスをチェックしたかを検証します。 これは、アプリケーションのサービス利用規約、文章を読んでいるのかの確認、その他同種のことで、ユーザーに同意を求める際に使用されます。 この検証は非常にWebアプリケーション固有の性質を持ち、また「同意」のデータはデータベースに保存する必要はありません。 (このカラムフィールドが無くても、ヘルパーは仮想的に属性を作成してくれます。)
class Person < ActiveRecord::Base
validates :terms_of_service, acceptance: true
end
デフォルトのエラーメッセージは、"must be accepted"です。
また、:accept
オプションの受け取りが可能で、同意した際に検証する値を決めることが出来ます。
デフォルトは、"1"で、他のものにしたければ下記のようにして簡単に変更することが出来ます。
class Person < ActiveRecord::Base
validates :terms_of_service, acceptance: { accept: 'yes' }
end
2.2 validates_associated
このヘルパーは、モデルが他のモデルに関連付けられていて検証が必要な場合に使用すべきです。
オブジェクトを保存しようとした際に、関連付けられたオブジェクトそれぞれでvalid?
が呼び出されます。
class Library < ActiveRecord::Base
has_many :books
validates_associated :books
end
この検証は、全ての関連付けのタイプで動作します。
validates_associated
を関連付けの両方で使用しないでください。
相互に呼び出しを行い、無限ループが発生してしまいます。
validates_associated
のデフォルトのエラーメッセージは、"is invalid"です。
関連付けられた各オブジェクトは、自身のerrors
コレクションを持ち、
errors
は呼び出し元のモデルを、把握しない(翻訳に自信無し)ことに注意してください。
2.3 confirmation
このヘルパーは、2つの入力欄に同じ値が入力されているかを検証する際に使用されます。 例えば、メールアドレスやパスワードを確認したい場合などです。 この検証は、確認用に"_confirmation"が付加されたフィールド名の仮想の属性を作成します。
class Person < ActiveRecord::Base
validates :email, confirmation: true
end
ビューは、次のようにします。
<%= text_field :person, :email %>
<%= text_field :person, :email_confirmation %>
このチェックは、email_confirmation
がnilで無かった場合にのみ動作します。
必須の確認を行うには、presence
チェックを追加してください。
(後述のpresence
を確認してください。)
class Person < ActiveRecord::Base
validates :email, confirmation: true
validates :email_confirmation, presence: true
end
デフォルトのエラーメッセージは、"doesn't match confirmation"です。
2.4 exclusion
このヘルパーは属性の値が、与えられた集合に含まれていないを検証します。 この集合には、任意の列挙可能なオブジェクトを指定することが可能です。
class Account < ActiveRecord::Base
validates :subdomain, exclusion: { in: %w(www us ca jp),
message: "Subdomain %{value} is reserved." }
end
exclusionヘルパーは、:in
オプションを持ち、
これに指定された各値の場合、検証で拒否されます。
:in
は、:within
のエイリアスを持ち、同じ働きをします。
この例では、:message
オプションを使って、拒否された理由を表示するようにしています。
デフォルトのエラーメッセージは、"is reserved"です。
2.5 format
このヘルパーは、属性の値が:with
オプションに指定した正規表現にマッチするかどうかを検証します。
class Product < ActiveRecord::Base
validates :legacy_code, format: { with: /A[a-zA-Z]+z/,
message: "Only letters allowed" }
end
デフォルトのエラーメッセージは、"is invalid"です。
2.6 inclusion
このヘルパーは値が指定された集合に含まれているかどうかを検証します。 この集合には、任意の列挙可能なオブジェクトを指定することが可能です。
class Coffee < ActiveRecord::Base
validates :size, inclusion: { in: %w(small medium large),
message: "%{value} is not a valid size" }
end
inclusionヘルパーは、:in
オプションを持ち、
これに指定された各値の場合のみ、検証で受け入れられます。
:in
は、:within
のエイリアスを持ち、同じ働きをします。
この例では、:message
オプションを使って、受け入れられない理由を表示するようにしています。
デフォルトのエラーメッセージは、"is not included in the list"です。
2.7 length
このヘルパーは、値の長さを検証します。 このヘルパーは様々なオプションを持つため、様々な方法で長さの制約を指定することが出来ます。
class Person < ActiveRecord::Base
validates :name, length: { minimum: 2 }
validates :bio, length: { maximum: 500 }
validates :password, length: { in: 6..20 }
validates :registration_number, length: { is: 6 }
end
lengthの利用可能なオプションは下記のとおりです。
デフォルトのエラーメッセージは、検証内容によって異なります。
これらのメッセージを:wrong_length
、:too_long
、:too_short
オプションと、
%{count}
を制約としている数値のプレースホルダを使用することで、独自のメッセージを作成することが可能です。
また、:message
をここでも使用することが可能です。
class Person < ActiveRecord::Base
validates :bio, length: { maximum: 1000,
too_long: "%{count} characters is the maximum allowed" }
end
このヘルパーはデフォルトで文字数をカウントしますが、
:tokenizer
オプションを使用して、異なる方法に値を分けることが可能です。
class Essay < ActiveRecord::Base
validates :content, length: {
minimum: 300,
maximum: 400,
tokenizer: lambda { |str| str.scan(/w+/) },
too_short: "must have at least %{count} words",
too_long: "must have at most %{count} words"
}
end
デフォルトのエラーメッセージが複数あることに注意してください(例: "is too short (minimum is %{count} characters)")。
このようになっている理由は、:minimum
が1の場合、独自のメッセージを提供するか、
代わりにpresence: true
を使用すべきだからです。
:in
または:within
が1の最小限の指定がされている場合、
独自のメッセージを提供するか、優先的にpresenceを使用すべきです。
sizeヘルパーは、lengthへのエイリアスです。
2.8 numericality
このヘルパーは、属性が数値だけなのかを検証します。
デフォルトでは、任意の整数、浮動小数点数を許可します。
整数のみを許可したい場合は、:only_integer
にtrueを指定します。
/A[+-]?d+Z/
正規表現は、値の属性を検証します。
そうでなければ、値をFloat
を使用して数値にしようと試みます。
上記の正規表現は末尾に改行文字を許可することに注意してください。
class Player < ActiveRecord::Base
validates :points, numericality: true
validates :games_played, numericality: { only_integer: true }
end
また、:only_integer
は下記のオプションを受け入れる値の制約に付け加える事が可能です。
デフォルトのエラーメッセージは、"is not a number"です。
2.9 presence
このヘルパーは、属性が空では無いことを検証します。
これにはblank?
メソッドが使用され、nilか空白の文字列、どちらかでないかを調べます。
空白の文字列とは、空文字列、空白スペースのみで構成された文字列が対象となります。
class Person < ActiveRecord::Base
validates :name, :login, :email, presence: true
end
関連付けされたものを必須項目にしたい場合は、 関連付けられているオブジェクト自体が存在し、関連付けに外部キーが使用されていないか(翻訳に自信無し)を確認する必要があります。
class LineItem < ActiveRecord::Base
belongs_to :order
validates :order, presence: true
end
関連付けされたレコードを必須とするには、
:inverse_of
オプションを関連付けに指定する必要があります。
class Order < ActiveRecord::Base
has_many :line_items, inverse_of: :order
end
has_one
、has_many
を通して関連付けられたオブジェクトの必須検証をする場合、
オブジェクトがblank?
、marked_for_destruction?
のどちらでも無いことを調べます。
false.blank?
はtrueであるため、booleanフィールドの必須検証をしたい場合は、
:field_name inclusion: { in: [true, false] }
を使用すべきです。
デフォルトのエラーメッセージは、"can't be empty"です。
2.10 absence
このヘルパーは、指定された属性の値が空であることを検証します。
これにはpresent?
メソッドが使用され、nilか空白の文字列、どちらでも無いかを調べます。
空白の文字列とは、空文字列、空白スペースのみで構成された文字列が対象となります。
class Person < ActiveRecord::Base
validates :name, :login, :email, absence: true
end
関連付けされたものが存在しないようにしたい場合は、 関連付けられているオブジェクト自体が存在せず、関連付けに外部キーが使用されていないか(翻訳に自信無し)を確認する必要があります。
class LineItem < ActiveRecord::Base
belongs_to :order
validates :order, absence: true
end
関連付けされたレコードが存在しないことを必須とするには、
:inverse_of
オプションを関連付けに指定する必要があります。
class Order < ActiveRecord::Base
has_many :line_items, inverse_of: :order
end
has_one
、has_many
を通して関連付けられたオブジェクトが存在しないことを検証をする場合、
オブジェクトがpresent?
、marked_for_destruction?
のどちらでも無いことを調べます。
false.present?
はfalseであるため、booleanフィールドの必須検証をしたい場合は、
:field_name exclusion: { in: [true, false] }
を使用すべきです。
デフォルトのエラーメッセージは、"must be blank"です。
2.11 uniqueness
このヘルパーは、属性の値がオブジェクトが保存される直前に一意であることを検証します。 ただし、データベースの一意制約を作るわけではないので、異なるデータベース接続によって 一意指定されているカラムに対し、同じ値が入ってしまうことがあるかもしれません。 これを避けるために、データベースにユニークインデックスを作成するようにしてください。
class Account < ActiveRecord::Base
validates :email, uniqueness: true
end
この検証では、モデルのテーブルに対しSQLクエリーを発行し、 同じ値のレコードが存在しないかを検索します。
他の属性に指定することで、一意制約の範囲の指定を行うの事ができる:scope
オプションがあります。
class Holiday < ActiveRecord::Base
validates :name, uniqueness: { scope: :year,
message: "should happen once per year" }
end
また、一意制約の際に大文字と小文字を区別するか、しないかを決定する:case_sensitive
オプションもあります。
このオプションのデフォルトはtrueです。
class Person < ActiveRecord::Base
validates :name, uniqueness: { case_sensitive: false }
end
いずれにしても大文字・小文字を区別した検索が行われるように設計されたデータベースがある事に注意してください。
デフォルトのエラーメッセージは、"has already been taken"です。
2.12 validates_with
このヘルパーは、検証のために別のクラスにレコードを渡します。
class Person < ActiveRecord::Base
validates_with GoodnessValidator
end
class GoodnessValidator < ActiveModel::Validator
def validate(record)
if record.first_name == "Evil"
record.errors[:base] << "This person is evil"
end
end
end
record.errors[:base]
は、特定の属性では無く、全体の状態に関するエラーを追加します。
validates_with
ヘルパーには、検証に使用するクラス、または複数のクラスのリストを指定します。
validates_with
には、デフォルトのエラーメッセージが無いため、
検証クラス内で、レコードのエラーコレクションに手動でエラーを追加しなければいけません。
検証メソッドの実装には、パラメーターが定義されているレコードを持たなければいけません。
他の全ての検証のように、validates_with
は:if
、
:unless
、:on
オプションを指定することが出来ます。
もし、他のオプションを渡すと、それらのオプションは検証クラスのオプションとして渡されます。
class Person < ActiveRecord::Base
validates_with GoodnessValidator, fields: [:first_name, :last_name]
end
class GoodnessValidator < ActiveModel::Validator
def validate(record)
if options[:fields].any?{|field| record.send(field) == "Evil" }
record.errors[:base] << "This person is evil"
end
end
end
この検証は、検証実行毎にでは無く、アプリケーションのライフサイクル全体で1度だけしか初期化されないことに注意してください。 そのため、内部のインスタンス変数の使用について注意が必要です。
インスタンス変数を使用した検証が複雑になってしまう場合は、 簡単にするために、代わりにプレーンな古いRubyオブジェクトを使用することも可能です。
class Person < ActiveRecord::Base
validate do |person|
GoodnessValidator.new(person).validate
end
end
class GoodnessValidator
def initialize(person)
@person = person
end
def validate
if some_complex_condition_involving_ivars_and_private_methods?
@person.errors[:base] << "This person is evil"
end
end
# …
end
2.13 validates_each
このヘルパーは、属性の検証をブロックを通して行います。 検証関数は予め定義されていないため、使用するブロックを1つ作成し、 渡された各属性毎に調べるようにしなければいけません。 下記の例では、nameとsurnameが小文字から始まっていないことを検証しています。
class Person < ActiveRecord::Base
validates_each :name, :surname do |record, attr, value|
record.errors.add(attr, 'must start with upper case') if value =~ /A[a-z]/
end
end
ブロックはレコード、属性名、属性の値を受け取ります。 ブロック内で、正当なデータであるかどうかを好きなように検証することが可能です。 もし、検証を失敗とするのであれば、不当なデータであるとするために、モデルにエラーメッセージを追加してください。
3. 共通の検証オプション
共通の検証オプションです。
3.1 :allow_nil
:allow_nil
オプションは、検証する値がnilの場合、検証をスキップします。
class Coffee < ActiveRecord::Base
validates :size, inclusion: { in: %w(small medium large),
message: "%{value} is not a valid size" }, allow_nil: true
end
3.2 :allow_blank
:allow_blank
オプションは、:allow_nil
に似ています。
属性の値がnilまたは空文字列のようにblank?に該当する場合は、検証をパスさせます。
class Topic < ActiveRecord::Base
validates :title, length: { is: 5 }, allow_blank: true
end
Topic.create("title" => "").valid? # => true
Topic.create("title" => nil).valid? # => true
3.3 :message
これまで見てきたとおり、:message
オプションに指定したメッセージが、検証が失敗した際にerrorsコレクションに追加されます。
このオプションを指定しない場合、Active Recordは各検証ヘルパーのデフォルトのメッセージを適用します。
3.4 :on
:on
オプションは、検証を実行するタイミングを指定します。
デフォルトでは、全ての組み込み検証ヘルパーは保存時に実行します。(新規作成、更新の両方)
on: :create
と指定することで新規作成時のみに、また、
on: :update
とすると更新時のみに検証するように変更することが可能です。
class Person < ActiveRecord::Base
# 更新時であれば、重複したメールが登録可能です。
validates :email, uniqueness: true, on: :create
# 新規作成時であれば、数字ではない値が登録可能です。
validates :age, numericality: true, on: :update
# デフォルト状態(検証は新規作成、更新時の両方で行われる)
validates :name, presence: true, on: :save
end
最後の行は、現在見直しているようです。 issueで議論されているように、 Rails 3.2のバージョンで動作しません。
4. 厳密な検証
検証を厳密にするよう指定する事も可能で、これを指定することで、 検証が失敗した際に、ActiveModel::StrictValidationFailedを発生させるようになります。
class Person < ActiveRecord::Base
validates :name, presence: { strict: true }
end
Person.new.valid? # => ActiveModel::StrictValidationFailed: Name can't be blank
また、:strict
オプションにカスタム例外を指定することが可能です。
class Person < ActiveRecord::Base
validates :token, presence: true, uniqueness: true, strict: TokenGenerationException
end
Person.new.valid? # => TokenGenerationException: Token can't be blank
5. 条件付きの検証
時折、ある条件を満たした場合にのみ、検証を行いたいというケースがありますが、
:if
と:unless
オプションを使用することで、これを行うことができます。
これらのオプションには、シンボル、文字列、Proc、配列のいずれかを指定します。
:if
オプションには、検証を実行したい条件を指定し、
:unless
オプションには、検証を実行しない条件を指定します。
5.1 :if
と:unless
にシンボルを指定
:if
と:unless
オプションにシンボルを指定すると、そのシンボル名に一致するメソッドが
検証が実行される直前に呼び出されます。
このオプションで、最も一般的に使用されています。
class Order < ActiveRecord::Base
validates :card_number, presence: true, if: :paid_with_card?
def paid_with_card?
payment_type == "card"
end
end
5.2 :if
と:unless
に文字列を指定
文字列を指定すると、evalによって評価されます。そのため、正しいRubyコードにする必要があります。 これを使用するのは、本当に短い条件で指定出来る場合のみに限定すべきです。
class Person < ActiveRecord::Base
validates :surname, presence: true, if: "name.nil?"
end
5.3 :if
と:unless
にProcを指定
Procオブジェクトを使用すると、メソッドを分けずにインラインで条件を書く事が可能です。 1行で書くのに非常に適しています。
class Account < ActiveRecord::Base
validates :password, confirmation: true,
unless: Proc.new { |a| a.password.blank? }
end
5.4 条件付き検証のグループ化
1つの条件に対し複数の検証を適用したい場合、
with_options
を使用することで簡単にそれを実現することが可能です。
class User < ActiveRecord::Base
with_options if: :is_admin? do |admin|
admin.validates :password, length: { minimum: 10 }
admin.validates :email, presence: true
end
end
if: :is_admin?
条件を満たすと、with_options
ブロック内の検証が行われます。
5.5 検証条件を連結
複数の条件を定義する際に、検証を実行するかしないかを配列によって指定することが可能です。
更に:if
と:unless
を同じ検証で適用することが可能です。
class Computer < ActiveRecord::Base
validates :mouse, presence: true,
if: ["market.retail?", :desktop?]
unless: Proc.new { |c| c.trackpad.present? }
end
全ての:if
内の条件を満たし、且つ:unless
内の条件を満たさない場合にのみ、検証は実行されます。
6. カスタム検証の実行
組み込みの検証ヘルパーの機能が要件を十分に満たせない場合、 好きなように自身のValidators、またはvalidate(検証)メソッドを書くことが可能です。
6.1 カスタムValidators
カスタムValidatorsは、ActiveModel::Validatorを拡張したクラスです。
これらのクラスは、引数としてレコードを受け取り、それを検証するvalidateメソッドを実装しなければいけません。
カスタムValidatorは、validates_with
メソッドを使用して呼び出されます。
class MyValidator < ActiveModel::Validator
def validate(record)
unless record.name.starts_with? 'X'
record.errors[:name] << 'Need a name starting with X please!'
end
end
end
class Person
include ActiveModel::Validations
validates_with MyValidator
end
カスタムValidatorsを追加して、個別の属性を検証する簡単な方法は、 便利なActiveModel::EachValidatorを使用することです。 このケースでは、カスタムValidatorクラスは、3つの引数(レコード、属性、値)を受け取る validate_eachメソッドを実装しなければいけません。
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
record.errors[attribute] << (options[:message] || "is not an email")
end
end
end
class Person < ActiveRecord::Base
validates :email, presence: true, email: true
end
例で見てきたように、自身のカスタムValidatorと標準の検証を組み合わせることもできます。
6.2 カスタムメソッド
また、モデルの状態を検証して正しくなければ、errorsコレクションにメッセージを追加するメソッドを作成することも可能です。
vaidate
クラスメソッドに検証メソッド名をシンボルとして渡して、メソッドを登録しなければいけません。
各クラスのメソッドに複数のシンボルを渡すことができ、 それぞれ渡されたのと同じ順序で検証が実行されます。
class Invoice < ActiveRecord::Base
validate :expiration_date_cannot_be_in_the_past,
:discount_cannot_be_greater_than_total_value
def expiration_date_cannot_be_in_the_past
if expiration_date.present? && expiration_date < Date.today
errors.add(:expiration_date, "can't be in the past")
end
end
def discount_cannot_be_greater_than_total_value
if discount > total_value
errors.add(:discount, "can't be greater than total value")
end
end
end
デフォルトでは、valid?
が呼び出される度に、このような検証が毎回実行されます。
また、これらのカスタム検証を実行する際に、:on
オプションに:create
または:update
を使用して、
制御することも可能です。
class Invoice < ActiveRecord::Base
validate :active_customer, on: :create
def active_customer
errors.add(:customer_id, "is not active") unless customer.active?
end
end
7. 検証のエラーの動作
これまでに説明してきたvalid?とinvalid?に加え、 Railsには、errorsコレクションのための作業や、オブジェクトの妥当性などを調べるための多くのメソッドが用意されています。
以降に、一般的によく使用されているメソッドについて説明していきます。 全ての利用可能なメソッドを確認したい場合は、ActiveModel::Errorsドキュメントを参照してください。
7.1 errors
全てのエラーを含むActiveModel::Errorsクラスのインスタンスを返します。 各キーは属性名で、値は全エラーメッセージ文字列の配列になっています。
class Person < ActiveRecord::Base
validates :name, presence: true, length: { minimum: 3 }
end
person = Person.new
person.valid? # => false
person.errors
# => {:name=>["can't be blank", "is too short (minimum is 3 characters)"]}
person = Person.new(name: "John Doe")
person.valid? # => true
person.errors # => []
7.2 errors[]
errors[]
は、特定の属性のエラーメッセージを調べたい場合に使用されます。
指定した属性に対する全てのエラーメッセージの配列が返されます。
もし、指定した属性にエラーが無ければ、空の配列が返されます。
class Person < ActiveRecord::Base
validates :name, presence: true, length: { minimum: 3 }
end
person = Person.new(name: "John Doe")
person.valid? # => true
person.errors[:name] # => []
person = Person.new(name: "JD")
person.valid? # => false
person.errors[:name] # => ["is too short (minimum is 3 characters)"]
person = Person.new
person.valid? # => false
person.errors[:name]
# => ["can't be blank", "is too short (minimum is 3 characters)"]
7.3 errors.add
add
メソッドは、特定の属性に関連するメッセージの追加をさせてくれます。
errors.full_messages
または、errors.to_a
メソッドを使用して、
ビューのフォーム内にユーザへのメッセージを表示させることが可能です。
個々のメッセージは、属性名を先頭に配置します。(且つ、語頭を大文字にします)
add
は、メッセージを追加したい属性名と、そのメッセージを受け取ります。
class Person < ActiveRecord::Base
def a_method_used_for_validation_purposes
errors.add(:name, "cannot contain the characters !@#%*()_-+=")
end
end
person = Person.create(name: "!@#")
person.errors[:name]
# => ["cannot contain the characters !@#%*()_-+="]
person.errors.full_messages
# => ["Name cannot contain the characters !@#%*()_-+="]
[]= setter
で同様の事が出来ます。
class Person < ActiveRecord::Base
def a_method_used_for_validation_purposes
errors[:name] = "cannot contain the characters !@#%*()_-+="
end
end
person = Person.create(name: "!@#")
person.errors[:name]
# => ["cannot contain the characters !@#%*()_-+="]
person.errors.to_a
# => ["Name cannot contain the characters !@#%*()_-+="]
7.4 errors[:base]
特定の属性ではなく、オブジェクトの状態全体に関連づいたエラーメッセージを追加することが可能です。
属性の値に気にすることなく、このメソッドを使用して、このオブジェクトは不正であるとすることが可能です。
errors[:base]
は配列であるため、単に文字列を追加することで、エラメッセージとして使用されます。
class Person < ActiveRecord::Base
def a_method_used_for_validation_purposes
errors[:base] << "This person is invalid because ..."
end
end
7.5 errors.clear
clear
メソッドは、故意にerrorsコレクションのメッセージを全て消去したい場合に使用されます。
もちろん、errors.clear
を呼び出すことは、不当なオブジェクトを正当なものにするわけではなく、
errorsコレクションをその時点では空にしますが、その後にvalid?
または他のメソッドを呼んで、
このオブジェクトをデータベースに保存しようとすると、再び検証が実行されます。
もし、検証でエラーが出れば、再びerrorsコレクションにメッセージが追加されます。
class Person < ActiveRecord::Base
validates :name, presence: true, length: { minimum: 3 }
end
person = Person.new
person.valid? # => false
person.errors[:name]
# => ["can't be blank", "is too short (minimum is 3 characters)"]
person.errors.clear
person.errors.empty? # => true
p.save # => false
p.errors[:name]
# => ["can't be blank", "is too short (minimum is 3 characters)"]
7.6 errors.size
sizeメソッドは、オブジェクトのエラーメッセージの総数を返します。
class Person < ActiveRecord::Base
validates :name, presence: true, length: { minimum: 3 }
end
person = Person.new
person.valid? # => false
person.errors.size # => 2
person = Person.new(name: "Andrea", email: "[email protected]")
person.valid? # => true
person.errors.size # => 0
8. ビューへの検証エラーの表示
検証を追加されたモデルに対し、Webフォームを介してモデルのインスタンスが作成され、それを検証した結果に1でもエラーがある場合、 画面にエラーメッセージを表示したいと考えるはずです。
アプリケーション毎に、この種の扱いが異なるため、 Railsはビューヘルパーに直接これらのメッセージを生成するような機能を持たせていませんが、 Railsは豊富なメソッドを持つため、最終的にはそれを容易に実現させてくれます。 加えてscaffoldで生成すると、Railsは_form.html.erb内に、 モデルの全てのerrorsのメッセージを表示するコードを生成します。
仮に、保存対象となるモデルのインスタンス変数@postがある場合、次のようになります。
<% if @post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% @post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
更に、Railsのフォームヘルパーでフォームを作成した場合、 検証でエラーが発生すると、入力欄を下記のように囲う<div>を生成します。
<div class="field_with_errors">
<input id="post_title" name="post[title]" size="30" type="text" value="">
</div>
このDIVに対し、好きなようにスタイルを指定することも出来ます。 デフォルトのscaffoldでは、Railsは例として下記のようなCSSを適用します。
.field_with_errors {
padding: 2px;
background-color: red;
display: table;
}
このスタイルは、エラーのあった入力欄を2pxの赤いボーダーで囲います。
© 2010 - 2017 STUDIO KINGDOM