10 バリデーション - Reference Documentation
Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith
Version: 2.3.0
Translated by: T.Yamamoto, Japanese Grails Doc Translating Team. Special thanks to NTT Software.
【注意】このドキュメントの内容はスナップショットバージョンを元に*意訳*されているため、一部現行バージョンでは未対応の機能もあります。
Table of Contents
10 バリデーション
Grails validation capability is built on Spring's Validator API and data binding capabilities. However Grails takes this further and provides a unified way to define validation "constraints" with its constraints mechanism.
Grailsのバリデーションは、SpringのバリデーションAPIとデータバインディングに基づいて実装されています。Grailsではこれらを発展させ、制約(constraints
)によってバリデーションを定義するすてきな仕組みを持っています。Constraints in Grails are a way to declaratively specify validation rules. Most commonly they are applied to domain classes, however URL Mappings and Command Objects also support constraints.
Grailsにおける制約は、バリデーションのルールを宣言的に定義する手段です。多くの場合ドメインクラスで利用されますが、URLマッピングやコマンドオブジェクトでも制約をサポートしています。
10.1 制約を宣言
Within a domain class constraints are defined with the constraints property that is assigned a code block:
ドメインクラスの制約は、次のようなconstraintsプロパティによって指定します。class User { String login String password String email Integer age static constraints = { … } }
You then use method calls that match the property name for which the constraint applies in combination with named parameters to specify constraints:
次に、プロパティ名と同じ名前のメソッド呼び出しで、適用したい制約とパラメータの組み合わせを与えます。class User { ... static constraints = { login size: 5..15, blank: false, unique: true password size: 5..15, blank: false email email: true, blank: false age min: 18 } }
In this example we've declared that the
この例では、login
property must be between 5 and 15 characters long, it cannot be blank and must be unique. We've also applied other constraints to the password
, email
and age
properties.login
プロパティに対して5~15文字の長さとし(size
)、空白(blank
)を許可せず、一意となる(unique
)よう制約を与えています。password
、email
、age
の各プロパティについても同様に制約を宣言しています。
By default, all domain class properties are not nullable (i.e. they have an implicit nullable: false
constraint).
デフォルトでは、すべてのドメインクラスのプロパティはnull値を許容しません(暗黙にnullable: false
制約を持っています)。
A complete reference for the available constraints can be found in the Quick Reference section under the Constraints heading.
利用可能な制約のリファレンスは、クイックリファレンスの見出し constraints で見ることができます。Note that constraints are only evaluated once which may be relevant for a constraint that relies on a value like an instance of
java.util.Date
.java.util.Date
のインスタンスのような値を必要とするかもしれないため、制約が評価されるのは一度だけであることに注意してください。class User { ... static constraints = { // this Date object is created when the constraints are evaluated, not // each time an instance of the User class is validated. birthDate max: new Date() } }
class User { ... static constraints = { // この Date 型オブジェクトは制約が評価されるときに作られます。 // User クラスのインスタンスがバリデーションされる度に作られるわけではありません。 birthDate max: new Date() } }
h3. A word of warning - referencing domain class properties from constraints
忠告 - 制約からドメインクラスのプロパティを参照するとき
It's very easy to attempt to reference instance variables from the static constraints block, but this isn't legal in Groovy (or Java). If you do so, you will get a
静的な制約の宣言からインスタンス変数を参照するのは非常に簡単ですが、これはGroovy(やJava)において適切ではありません。この場合、困ったことにMissingPropertyException
for your trouble. For example, you may tryMissingPropertyException
が発生します。たとえば、以下のようなコードを試してみると…class Response { Survey survey Answer answer static constraints = { survey blank: false answer blank: false, inList: survey.answers } }
See how the
このように、inList
constraint references the instance property survey
? That won't work. Instead, use a custom validator:inList
制約においてインスタンスプロパティであるsurvey
を参照すると、これは動作しません。代わりに、カスタムvalidatorを使いましょう:class Response { … static constraints = { survey blank: false answer blank: false, validator: { val, obj -> val in obj.survey.answers } } }
In this example, the
この例では、カスタムバリデータの引数obj
argument to the custom validator is the domain instance that is being validated, so we can access its survey
property and return a boolean to indicate whether the new value for the answer
property, val
, is valid.obj
は、バリデーションされるドメインクラスの インスタンス です。こうすることでsurvey
プロパティにアクセスし、answer
プロパティの新しい値としてval
がsurvey.answers
に含まれるかどうかを示す真偽値を得ることができます。
10.2 制約をバリデートする
h4. Validation Basics
バリデーションの基礎
Call the validate method to validate a domain class instance:
ドメインクラスのインスタンスをバリデーションするには、validateメソッドを呼び出します:def user = new User(params)if (user.validate()) { // do something with user } else { user.errors.allErrors.each { println it } }
The
ドメインクラスのerrors
property on domain classes is an instance of the Spring Errors interface. The Errors
interface provides methods to navigate the validation errors and also retrieve the original values.errors
プロパティは、SpringのErrorsインターフェイスのインスタンスです。Errors
インターフェイスは、バリデーションエラーの参照や元の値の取得などのメソッドを提供します。h4. Validation Phases
バリデーションのフェーズ
Within Grails there are two phases of validation, the first one being data binding which occurs when you bind request parameters onto an instance such as:
Grailsではバリデーションに2つのフェーズがあります。1つ目はdata bindingであり、インスタンスにリクエストパラメータをバインドするときに発生します:def user = new User(params)
At this point you may already have errors in the
この時点で既に型変換に起因するerrors
property due to type conversion (such as converting Strings to Dates). You can check these and obtain the original input value using the Errors
API:errors
プロパティが存在する場合があります(文字列を日付に変換しようとするなど)。Errors
APIを使用することで、エラーの有無や元の入力値を取得することができます:if (user.hasErrors()) { if (user.errors.hasFieldErrors("login")) { println user.errors.getFieldError("login").rejectedValue } }
The second phase of validation happens when you call validate or save. This is when Grails will validate the bound values againts the constraints you defined. For example, by default the save method calls
バリデーションの2つ目のフェーズが発生するのは、validateやsaveが呼び出されたときです。
ここでは、バインドされた値をconstraintsの定義によってGrailsがバリデーションします。
たとえば、デフォルトでsaveメソッドはvalidate
before executing, allowing you to write code like:validate
を呼び出すので、次のようなコードが書けます:if (user.save()) { return user } else { user.errors.allErrors.each { println it } }
10.3 制約をクラス間で共有する
A common pattern in Grails is to use command objects for validating user-submitted data and then copy the properties of the command object to the relevant domain classes. This often means that your command objects and domain classes share properties and their constraints. You could manually copy and paste the constraints between the two, but that's a very error-prone approach. Instead, make use of Grails' global constraints and import mechanism.
ユーザが送信したデータのバリデーションにおいて、Grailsにおける一般的なパターンは、コマンドオブジェクト使い、コマンドオブジェクトのプロパティを該当のドメインクラスへコピーすることです。
これはしばしばコマンドオブジェクトとドメインクラスの間で、プロパティとそのプロパティに対する制約を共有することになります。
それぞれの制約を手動でコピー・アンド・ペーストすることもできますが、これは間違いを起こしやすいアプローチです。
代わりに、Grailsのグローバル制約とインポート機構を使用しましょう。Global Constraints
グローバル制約
In addition to defining constraints in domain classes, command objects and other validateable classes, you can also define them in
ドメインクラスやコマンドオブジェクト、他のバリデーション可能なクラス内で制約を定義するほかに、grails-app/conf/Config.groovy
:
grails-app/conf/Config.groovy
内でも制約を定義できます。grails.gorm.default.constraints = { '*'(nullable: true, size: 1..20) myShared(nullable: false, blank: false) }
These constraints are not attached to any particular classes, but they can be easily referenced from any validateable class:
これらの制約は特定のクラスへ関連付けられていませんが、バリデーション可能なクラスから簡単に参照できます:class User { ... static constraints = { login shared: "myShared" } }
Note the use of the
shared
argument, whose value is the name of one of the constraints defined in grails.gorm.default.constraints
. Despite the name of the configuration setting, you can reference these shared constraints from any validateable class, such as command objects.
shared
引数にはgrails.gorm.default.constraints
内に定義した制約の名前の1つを指定していることに注目してください。
このように設定ファイル内の名前であるにもかかわらず、コマンドオブジェクトのようなバリデーション可能なクラスから共有された制約を参照できます。
The '*' constraint is a special case: it means that the associated constraints ('nullable' and 'size' in the above example) will be applied to all properties in all validateable classes. These defaults can be overridden by the constraints declared in a validateable class.
「*」制約は特別な意味があります。この'*'
に関連した制約(上記の例ではnullable
とsize
)はバリデーション可能なクラス内のすべてのプロパティへ適用されます。
これらのデフォルト設定はバリデーション可能なクラス内で宣言する制約によって上書き可能です。Importing Constraints
制約をインポートする
Grails 2 introduced an alternative approach to sharing constraints that allows you to import a set of constraints from one class into another.
Grails 2では共有制約に代わる、あるクラスから他のクラスへ制約のセットをインポートするというアプローチを導入しました。
Let's say you have a domain class like so:
以下のようなドメインクラスがあるとしましょう:class User { String firstName String lastName String passwordHash static constraints = { firstName blank: false, nullable: false lastName blank: false, nullable: false passwordHash blank: false, nullable: false } }
You then want to create a command object,
このとき、ドメインクラスのプロパティと同じプロパティを持ち、そのプロパティに付随する制約が定義された、コマンドオブエクトを作りたいとします。
これはUserCommand
, that shares some of the properties of the domain class and the corresponding constraints. You do this with the importFrom()
method:
importFrom()
メソッドで実現できます:class UserCommand { String firstName String lastName String password String confirmPassword static constraints = { importFrom User password blank: false, nullable: false confirmPassword blank: false, nullable: false } }
This will import all the constraints from the
これはUser
domain class and apply them to UserCommand
. The import will ignore any constraints in the source class (User
) that don't have corresponding properties in the importing class (UserCommand
). In the above example, only the 'firstName' and 'lastName' constraints will be imported into UserCommand
because those are the only properties shared by the two classes.
User
ドメインクラスからすべての制約をインポートし、UserCommand
へこれらの制約を適用します。
このインポートは、インポート先のクラス(UserCommand
)に関係がないプロパティの場合、インポート元のクラス(User
)内のそのプロパティの制約を無視します。
上記の例では、firstName
とlastName
のみが両方のクラスで共有されてるため、これらの制約のみがUserCommand
へインポートされます。
If you want more control over which constraints are imported, use the
もし、インポートする制約をより細かく制御したい場合、include
and exclude
arguments. Both of these accept a list of simple or regular expression strings that are matched against the property names in the source constraints. So for example, if you only wanted to import the 'lastName' constraint you would use:
include
とexclude
の引数が使えます。
両者ともに、インポート元の制約のプロパティ名に一致する単なる文字列、または正規表現文字列のリストを受け取ります。
例えば、lastName
制約だけをインポートしたい場合は以下のように使います:… static constraints = { importFrom User, include: ["lastName"] … }
or if you wanted all constraints that ended with 'Name':
またはName
で終わるすべての制約をインポートしたい場合:…
static constraints = {
importFrom User, include: [/.*Name/]
…
}
Of course,
もちろんexclude
does the reverse, specifying which constraints should not be imported.
exclude
はこの逆で、インポートすべきでない制約を指定します。
10.4 クライアントサイドバリデーション
Displaying Errors
エラーを表示する
Typically if you get a validation error you redirect back to the view for rendering. Once there you need some way of displaying errors. Grails supports a rich set of tags for dealing with errors. To render the errors as a list you can use renderErrors:
一般的にバリデーションエラーが発生した場合は、レンダリングをするために元のビューへリダイレクトします。
このとき、何らかのエラー表示の手段が必要になります。
Grailsではエラーを扱うためのリッチなタグセットを提供しています。
エラーを一覧表示するにはrenderErrorsを使います:<g:renderErrors bean="${user}" />
<g:hasErrors bean="${user}"> <ul> <g:eachError var="err" bean="${user}"> <li>${err}</li> </g:eachError> </ul> </g:hasErrors>
Highlighting Errors
エラーをハイライトする
It is often useful to highlight using a red box or some indicator when a field has been incorrectly input. This can also be done with the hasErrors by invoking it as a method. For example:
多くの場合、フィールドが不正入力されたとき、ボックスを赤くしたり、何らかの印を使ってハイライトをすると便利です。
これもhasErrorsをメソッドとして実行することで実現できます。
例えば:<div class='value ${hasErrors(bean:user,field:'login','errors')}'> <input type="text" name="login" value="${fieldValue(bean:user,field:'login')}"/> </div>
This code checks if the
このコードはlogin
field of the user
bean has any errors and if so it adds an errors
CSS class to the div
, allowing you to use CSS rules to highlight the div
.
user
ビーンのlogin
フィールドにエラーがあるかどうかをチェックし、エラーがある場合にはdiv
にerros
というCSSのクラスを追加するので、dev
をハイライトするCSSルールが使えるようになります。Retrieving Input Values
入力値を取得する
Each error is actually an instance of the FieldError class in Spring, which retains the original input value within it. This is useful as you can use the error object to restore the value input by the user using the fieldValue tag:
それぞれのエラーは実際にはSpringのFieldErrorクラスのインスタンスで、インスタンス内にオリジナルの入力値を保持しています。
これはfieldValueタグを使いエラーオブジェクトから入力値を復元するときに役立ちます:<input type="text" name="login" value="${fieldValue(bean:user,field:'login')}"/>
This code will check for an existing
このコードはFieldError
in the User
bean and if there is obtain the originally input value for the login
field.
User
ビーン内にFieldError
が存在するかチェックし、もし存在する場合はlogin
フィールドに対する元の入力値を取得します。
10.5 バリデーションの国際化
Another important thing to note about errors in Grails is that error messages are not hard coded anywhere. The FieldError class in Spring resolves messages from message bundles using Grails' i18n support.
このほかに、Grailsのエラーに関して重要なことは、エラーメッセージがどこにもハードコードされていないということです。
SpringのFieldErrorクラスは、Grailsのi18nサポートを使いメッセージバンドルからメッセージを解決します。Constraints and Message Codes
制約とメッセージコード
The codes themselves are dictated by a convention. For example consider the constraints we looked at earlier:
このコード自体は規約によって決められています。
例えば、以下のような制約について考えてみます:package com.mycompany.myappclass User { ... static constraints = { login size: 5..15, blank: false, unique: true password size: 5..15, blank: false email email: true, blank: false age min: 18 } }
If a constraint is violated Grails will by convention look for a message code of the form:
もし制約に違反している場合、Grailsは規約により以下の形式に従いメッセージコードを探します:[Class Name].[Property Name].[Constraint Code]
In the case of the
blank
constraint this would be user.login.blank
so you would need a message such as the following in your grails-app/i18n/messages.properties
file:
blank
制約の場合はuser.login.blank
となり、grails-app/i18n/messages.properties
ファイル内に以下のようなメッセージが必要です:user.login.blank=Your login name must be specified!
The class name is looked for both with and without a package, with the packaged version taking precedence. So for example, com.mycompany.myapp.User.login.blank will be used before user.login.blank. This allows for cases where your domain class message codes clash with a plugin's.
このクラス名はパッケージ名有りとパッケージ名無しの両方で検索され、両方存在する場合はパッケージ名有りのバージョンが優先されます。
例えば、com.mycompany.myapp.User.login.blank
はuser.login.blank
よりも先に使われます。
これによりドメインクラスのメッセージコードがプラグインと競合した場合でも競合を回避できます。
For a reference on what codes are for which constraints refer to the reference guide for each constraint.
どの制約にどんなコードが対応しているかを調べるには、それぞれの制約に対するリファレンスガイドを参照してください。Displaying Messages
メッセージを表示する
The renderErrors tag will automatically look up messages for you using the message tag. If you need more control of rendering you can handle this yourself:
renderErrorsタグはmessageタグを使って自動的にメッセージを探します。
もし、より詳細な表示の制御が必要な場合は自分で制御できます:<g:hasErrors bean="${user}"> <ul> <g:eachError var="err" bean="${user}"> <li><g:message error="${err}" /></li> </g:eachError> </ul> </g:hasErrors>
In this example within the body of the eachError tag we use the message tag in combination with its
この例ではeachErrorタグのボディの中で、エラーに対するメッセージを取得するためmessageタグにerror
argument to read the message for the given error.
error
引数を組み合わせて使用しています。
10.6 コマンドオブジェクト、ドメインクラス以外のバリデーション
Domain classes and command objects support validation by default. Other classes may be made validateable by defining the static
ドメインクラスとコマンドオブジェクトはデフォルトでバリデーションをサポートしています。
他のクラスについては、(前述したように)そのクラス内で静的なconstraints
property in the class (as described above) and then telling the framework about them. It is important that the application register the validateable classes with the framework. Simply defining the constraints
property is not sufficient.
constraints
プロパティを定義し、それからフレームワークにこのクラスを教えてあげることで、バリデーション可能にすることができます。
アプリケーション側からバリデーション可能なクラスをフレームワークに登録するということが重要です。
単にconstraints
プロパティを定義しただけでは十分ではありません。The Validateable Annotation
Validateableアノテーション
Classes which define the static
クラスに静的なconstraints
property and are annotated with @Validateable can be made validateable by the framework. Consider this example:
constraints
プロパティを定義し、@Validateable
を付与することでフレームワークによってバリデーション可能となります。
例えば:// src/groovy/com/mycompany/myapp/User.groovy package com.mycompany.myappimport grails.validation.Validateable@Validateable class User { ... static constraints = { login size: 5..15, blank: false, unique: true password size: 5..15, blank: false email email: true, blank: false age min: 18 } }
Registering Validateable Classes
バリデーション可能なクラスの登録
If a class is not marked with
クラスにValidateable, it may still be made validateable by the framework. The steps required to do this are to define the static
constraints property in the class (as described above) and then telling the framework about the class by assigning a value to the
grails.validateable.classes property in
Config.groovy@:
@Validateable
が付与されていなくても、フレームワークによってバリデーション可能になっている場合があります。
アノテーションなしでバリデーション可能にするには、(前述したように)そのクラス内で静的なconstraints
プロパティを定義し、それからConfig.groovy
内のgrails.validateable.classes
プロパティに値を設定してフレームワークにこのクラスを教えてあげる必要があります:grails.validateable.classes = [com.mycompany.myapp.User, com.mycompany.dto.Account]