プロゲートで簡単なバリデーションを行なっていた。
lass User < ApplicationRecord
has_secure_password
validates :name, {presence: true}
validates :email, {presence: true, uniqueness:true}
.
.
.
end
目標
- railsガイドで書かれているバリデーションを実行する。
- バリデーションで引っ掛かったらエラーメッセージを表示させる。
まだこれからだけど
送信ボタンを押した時もバリデーションを実行できそうだ。
これは後から考える。
とりあえず同期しながら簡単なことを行なっていく。
目的と合うバリデーションオプション
:on
オプション バリデーションのタイミングを指定
:on
オプションはバリデーションを実行するタイミングを指定し、
:create
または:update
のいずれかの値を取ります。
:message
オプション errorsコレクションに追加するメッセージを指定
:messageオプションはバリデーション失敗時にerrorsコレクションに追加するメッセージを指定
します。
バリデーションヘルパーには、それぞれデフォルトのエラーメッセージが用意されています。
:messageオプションが使われていない場合はデフォルトのメッセージが使われます。利用可能なヘルパーを1つずつ見ていきましょう。
出典
目的と合うバリデーションヘルパー
2.8 length (属性の値の長さを検証)
このヘルパーは、属性の値の長さを検証します。多くのオプションがあり、さまざまな長さ制限を指定できます。
class Person < ApplicationRecord
validates :name, length: { minimum: 2 }
validates :bio, length: { maximum: 500 }
validates :password, length: { in: 6..20 }
validates :registration_number, length: { is: 6 }
end
利用できる長さ制限オプションは以下のとおりです。
:minimum:
属性はこの値より小さな値を取れません。
:maximum:
属性はこの値より大きな値を取れません。
:in
または:within:
属性の長さは、与えられた区間以内でなければなりません。このオプションの値は範囲でなければなりません。
:is:
属性の長さは与えられた値と等しくなければなりません。
デフォルトのエラーメッセージは、実行されるバリデーションの種類によって異なります。デフォルトのメッセージは:wrong_length
、:too_long
、:too_short
オプションを使ってカスタマイズすることも、%{count}を長さ制限に対応する数値のプレースホルダにも使えます。:message
オプションを使ってエラーメッセージを指定することもできます。
class Person < ApplicationRecord
validates :bio, length: { maximum: 1000,
too_long: "最大%{count}文字まで使えます" }
end
デフォルトのエラーメッセージは英語が複数形で表現されていることにご注意ください(例: "is too short (minimum is %{count} characters)")。このため、:minimumを1に設定するのであれば、メッセージをカスタマイズして単数形にするか、代わりにpresence: trueを使います。:inまたは:withinの下限に1を指定する場合``、メッセージをカスタマイズして単数形にするか、
lengthより先にpresenceを呼ぶ```ようにします。
2.10 presence (属性が空(empty)でない)
このヘルパーは、指定された属性が空(empty)でないことを確認します。値がnilや空文字でない、つまり空でもなければホワイトスペースでもないことを確認するために、内部でblank?メソッドを使っています。
class Person < ApplicationRecord
validates :name, :login, :email, presence: true
end
関連付けが存在することを確認したい場合、関連をマッピングするために使われる外部キーではなく、関連するオブジェクト自体が存在するかどうかを検証する必要があります。以下の例では、外部キーが空ではないことと、関連付けられたオブジェクトが存在することをチェックしています。
class Supplier < ApplicationRecord
has_one :account
validates :account, presence: true
end
関連付けられたレコードの存在が必須の場合、これを検証するには:inverse_ofオプションでその関連付けを指定する必要があります。
関連付けが存在し、かつ有効であることを確かめるには、validates_associatedも使う必要があります。
class Order < ApplicationRecord
has_many :line_items, inverse_of: :order
end
このヘルパーを使って、has_oneまたはhas_manyリレーションシップを経由して関連付けられたオブジェクトが存在することを検証すると、blank?でもなくmarked_for_destruction?(削除用マーク済み)でもないかどうかがチェックされます。
false.blank?は常にtrueなので、真偽値に対してこのメソッドを使うと正しい結果が得られません。真偽値の存在をチェックしたい場合は、以下のいずれかを使う必要があります。
validates :boolean_field_name, inclusion: [true, false]
validates :boolean_field_name, exclusion: [nil]
これらのバリデーションのいずれかを使うことで、値が決してnilにならないようにできます。nilがあると、ほとんどの場合NULL値になります。
出典
2.12 uniqueness (属性の値が一意(unique)であり重複していない)
このヘルパーは、オブジェクトが保存される直前に、属性の値が一意(unique)であり重複していないことを検証します。このヘルパーは一意性の制約をデータベース自体には作成しないので、本来一意にすべきカラムに、たまたま2つのデータベース接続によって同じ値を持つレコードが2つ作成される可能性が残ります。これを避けるには、データベースのそのカラムに一意インデックスを作成する必要があります。
class Account < ApplicationRecord
validates :email, uniqueness: true
end
このバリデーションは、その属性と同じ値を持つ既存のレコードがモデルのテーブルにあるかどうかを調べるSQLクエリを実行することで行われます。
このヘルパーには、一意性チェックの範囲を限定する別の属性を指定する:scopeオプションがあります。
class Holiday < ApplicationRecord
validates :name, uniqueness: { scope: :year,
message: "発生は年に1度である必要があります" }
end
:scopeを用いる一意性バリデーション違反を防止する目的でデータベース側に制約を作成したい場合は、データベース側で両方のカラムにuniqueインデックスを作成しなければなりません。MySQLのマニュアルでマルチカラムインデックスについての情報を参照するか、PostgreSQLのマニュアルでカラムのグループを参照する一意性制約についての例を参照してください。
このヘルパーには:case_sensitiveというオプションもあります。これは一意性制約で大文字小文字を区別するか、またはデータベースのデフォルトの照合順序(collation)を尊重するかどうかを定義できます。このオプションはデフォルトで、データベースのデフォルト照合順序を尊重します。
class Person < ApplicationRecord
validates :name, uniqueness: { case_sensitive: false }
end
一部のデータベースでは検索で常に大文字小文字を区別しない設定になっているものがあります。
デフォルトのエラーメッセージは「has already been taken」です。
出典
7.6 errors.clear (errorsコレクションに含まれるメッセージをすべてクリア)
clearメソッドは、errorsコレクションに含まれるメッセージをすべてクリアしたい場合に使えます。無効なオブジェクトに対してerrors.clearメソッドを呼び出しても、オブジェクトが実際に有効になるわけではありませんのでご注意ください。errorsは空になりますが、valid?やオブジェクトをデータベースに保存しようとするメソッドが次回呼び出されたときに、バリデーションが再実行されます。そしていずれかのバリデーションが失敗すると、errorsコレクションに再びメッセージが保存されます。
class Person < ApplicationRecord
validates :name, presence: true, length: { minimum: 3 }
end
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.empty?
=> false
irb> person.errors.clear
irb> person.errors.empty?
=> true
irb> person.save
=> false
irb> person.errors.empty?
=> false
出典
7.7 errors.size (合計数でエラー件数を表示できそうだ。)
sizeメソッドは、そのオブジェクトのエラーメッセージの合計数を返します。
class Person < ApplicationRecord
validates :name, presence: true, length: { minimum: 3 }
end
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.size
=> 2
irb> person = Person.new(name: "Andrea", email: "andrea@example.com")
irb> person.valid?
=> true
irb> person.errors.size
=> 0
8 バリデーションエラーをビューで表示する
モデルを作成してバリデーションを追加し、Webのフォーム経由でそのモデルが作成できるようになったら、そのモデルでバリデーションが失敗したときにエラーメッセージを表示したくなります。
エラーメッセージの表示方法はアプリケーションごとに異なるため、そうしたメッセージを直接生成するビューヘルパーはRailsに含まれていません。 しかし、Railsでは一般的なバリデーションメソッドが多数提供されているので、カスタムのメソッドを作成するのは比較的簡単です。また、生成をscaffoldで行なうと、そのモデルのエラーメッセージをすべて表示するERBがRailsによって一部の_form.html.erbファイルに追加されます。
@articleという名前のインスタンス変数に保存されたモデルがあるとすると、ビューは以下のようになります。
<% if @article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@article.errors.count, "error") %>が原因でこの記事を保存できませんでした</h2>
<ul>
<% @article.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
また、フォームをRailsのフォームヘルパーで生成した場合、あるフィールドでバリデーションエラーが発生すると、そのエントリの周りに追加の
<div class="field_with_errors">
<input id="article_title" name="article[title]" size="30" type="text" value="">
</div>
この