(Quick Reference)

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.
【注意】このドキュメントの内容はスナップショットバージョンを元に*意訳*されているため、一部現行バージョンでは未対応の機能もあります。

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)よう制約を与えています。passwordemailageの各プロパティについても同様に制約を宣言しています。

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 MissingPropertyException for your trouble. For example, you may try
静的な制約の宣言からインスタンス変数を参照するのは非常に簡単ですが、これはGroovy(やJava)において適切ではありません。この場合、困ったことにMissingPropertyExceptionが発生します。たとえば、以下のようなコードを試してみると…

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プロパティの新しい値としてvalsurvey.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 validate before executing, allowing you to write code like:
バリデーションの2つ目のフェーズが発生するのは、validatesaveが呼び出されたときです。 ここでは、バインドされた値をconstraintsの定義によってGrailsがバリデーションします。 たとえば、デフォルトでsaveメソッドは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.
「*」制約は特別な意味があります。この'*'に関連した制約(上記の例ではnullablesize)はバリデーション可能なクラス内のすべてのプロパティへ適用されます。 これらのデフォルト設定はバリデーション可能なクラス内で宣言する制約によって上書き可能です。

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)内のそのプロパティの制約を無視します。 上記の例では、firstNamelastNameのみが両方のクラスで共有されてるため、これらの制約のみが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:
もし、インポートする制約をより細かく制御したい場合、includeexcludeの引数が使えます。 両者ともに、インポート元の制約のプロパティ名に一致する単なる文字列、または正規表現文字列のリストを受け取ります。 例えば、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}" />

If you need more control you can use hasErrors and eachError:
もし、より詳細な制御が必要な場合はhasErrorseachErrorを使います:

<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フィールドにエラーがあるかどうかをチェックし、エラーがある場合にはdiverrosという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.myapp

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 } }

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.blankuser.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 error argument to read the message for the given error.
この例ではeachErrorタグのボディの中で、エラーに対するメッセージを取得するためmessageタグに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.myapp

import 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]