html Grails约束[验证]

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了html Grails约束[验证]相关的知识,希望对你有一定的参考价值。

# Constraints

Los constraints sirven para validar que los valores asignados a las propiedades sean válidos, además a través de GORM ayudan a la generación del esquema de la bd.

Los constraints se aplican en dos lugares: 

 * En el databinding (valida los datos de la vista) a través del método `validate()`.
 * Cuando se guarda el domain class (valida los datos hacia la bd) a través del método `save()`.


# Constraints Defaults

Por defecto, todas las propiedades de un domain/command object son `nullable: false` (obligatorias) y la única manera de cambiarlo es sobreescribiendo la propiedad. Por lo tanto si se agrega un `validator` personalizado, se mantendrá el constraint `nullable:false`.


# Nullable vs Blank

Cuando se realiza databinding en los input sin valor estos vienen como cadenas vacías, sin embargo el databinder convierte dichas cadenas vacías a `null` para que aplique el constraint por default de todas las propiedades `nullable:false`. No importa si la cadena tiene espacios `" "`, dicha cadena será convertida a `null`. Por lo tanto, no tiene mucho sentido manejar el constraint `blank` si los databinding solo provienen del `request`.

El constraint `blank` sirve para validar que una propiedad no esté en blanco después de aplicar un `trim`, por lo que rechaza los valores `""` o `" "`. Utilice `blank` para garantizar que un valor no entre a la bd en blanco ya que del request nunca vendrá una cadena vacía.


# Constraints exclusivos para cadenas

Existen algunos constraints que únicamente aplican para propiedades de tipo `String`, por ejemplo: `creditCard`, `email`, `matches`, `blank`, etc.


# max vs maxSize

`max`: Asegura que el valor no exceda a `max` 

`maxSize`: Asegura que el size de una colección no sobrepase a `maxSize`.

`min`: Asegura que el valor no sea menor a `min`

`minSize`: Asegura que el size de una colección no sea menor a `minSize`.


# size

Utiliza un `groovy range` para restringir el tamaño de una colección, un número o el length de un `String`

```
String telCelular
...

telCelular size: 8..15 // mínimo 8, máximo 15 (si acepta Strings de tamaño 8 y 15)
```


> Nota: Currently this constraint cannot be used in addition to blank or nullable. Use a custom validator for these combinations.


# Constraints property order

Los constraints de una propiedad se ejecutan en el orden que fueron definidos, en el siguiente ejemplo se ejecuta primero `email:true` y después el `validator`. Sin embargo todos los constraints son ejecutados y se van acumulando, es decir, aunque el nombre no sea un email válido se ejecutará el `validator`.

```
package com.testing

@Validateable
class Command1 {

    String yourEmail;

    static constraints = {
        yourEmail email:true, validator: { value ->
            if (value < 4) {
                return "erroneo"
            }
        }
    }
}
```

Esta regla no aplica para el constraint por default `nullable:false`, cuando no está presente es el primer constraint en evaluarse por lo tanto si la propiedad es `null` no se ejecutará ninguno de los subsecuentes constraints. Esto está bien para no estar evaluando valores `null` en las validaciones personalizadas.

Nota: Si se escribe el constraint `nullable:false` en una propiedad, no importa si está antes o después de un validator, siempre será el primero en evaluarse.

Las propiedades se escriben en el scaffolding de acuerdo a cómo aparecen en los constraints, se puede cambiar el orden de una propiedad declarándola con constraints vacíos:

```
@Validateable
class Command1 {
    String nombre
    String apellido

    static constraints = {
        nombre()
        apellido()
    }
}
```


# Validadores personalizados

Grails permite definir validadores personalizados en cualquier campo, para ello es necesario escribir un `validator` en los constraints el cual puede recibir 1, 2 o 3 parámetros, de acuerdo al número de parámetros es la manera como se agregan los mensajes de error. 


# Validator con 1 parámetro

Utilicelo cuando solo necesite el valor del campo para realizar la validación:

```
package com.testing

@Validateable
class Command1 {

    BigDecimal costoContrato = 0

    static constraints = {
        costoContrato validator: { value ->
            if (value < 4) {
                return "erroneo"
            }
        }
    }
}
```

# Validator con 2 parámetros

El primer parámetro es el valor introducido por el usuario sobre el campo (`value`), el segundo la instancia de la clase (`command1`). _La instancia de la clase siempre tendrá todos los valores introducidos por el usuario en todos los campos._

Cuando el `validator` recibe 2 parámetros, el mensaje de error se agrega retornando el código de error:


```
package com.testing

@Validateable
class Command1 {

    BigDecimal costoContrato = 0
    int maxCosto = 90

    static constraints = {
        costoContrato validator: { value, command1 ->
            if (value < command1.maxCosto) {
                return "erroneo"
            }
        }
    }
}
```

En el ejemplo anterior, la llave `"erroneo"` será buscada en `messages.properties` como:

`com.testing.Command1.erroneo` ó `erroneo`


# Validator con 2 parámetros y argumentos

```
package com.testing

@Validateable
class Command1 {

    BigDecimal costoContrato = 0

    static constraints = {
        costoContrato validator: { value, command1 ->
            if (value < 4) {
                return ["erroneo", 97]
            }
        }
    }
}
```

`erroneo=El valor {2} es erroneo`


Los posibles placeholders que se pueden utilizar en el key de `messages.properties` son:

`{0}`: nombre del campo

`{1}`: Nombre completo de la clase

`{2}`: Valor introducido en la propiedad

`{3}`: primer parámetro del array

`{4}`: segundo parámetro del array

`{N}`: parámetro N del array.


# Validator con 3 parámetros

El `validator` que recibe 3 parámetros, recibe los mismos parámetros que el validador de 2 parámetros y un tercero que es el objeto `errors`. Cuando se utiliza esta versión por convensión se está indicando a Grails que los errores serán introducidos directamente en el objeto `errors` por lo que ya no se deberá retornar el código de error. En esta versión la manera de terminar la ejecución del validador es con un `return`.



```
pagoPrimerManto nullable: true, validator: { value, _this, errors ->
            // Cuando el número de mantenimientos del depósito inicial es 0, quiere decir que no se está incluyendo ningún
            def pagoPrimerMantoRequired = _this.numMantosDepIni==0
            if (pagoPrimerMantoRequired && value == null) {
                errors.rejectValue("pagoPrimerManto", "pagoPrimerManto.notnull", null, "")
                return
            }

            if (value[Calendar.YEAR] != _this.anioAReservar) {
                errors.rejectValue("pagoPrimerManto", "diferent.message", null, "")
            }

        }
```


# Validator general en los constraints

Se puede escribir un `validator` a nivel de propiedad que valide los valores de distintas propiedades del objeto, sin embargo no es lo más entendible ya que un validator a nivel de propiedad se entiende que sirve para validar de manera personalizada la propiedad donde se define.

Una manera de lograrlo es agregando _al command_ una propiedad extra que se encargará de validar todas las propiedades del objeto:


```
@Validateable
class Command1 {
    String nombre
    String apellido
    boolean customValidator

    static constraints = {
        customValidator nullable: true, validator: { value, command1, errors ->
            if (command1.nombre.equals(command1.apellido)) {
                errors.reject("nombreapellido.equals.error")
                return
            }
        }
    }
}
```

```
<g:form action="formSubmit">
    <g:hasErrors bean="${command1}">
        <div class="alert alert-danger">
            <g:renderErrors bean="${command1}" as="list"/>
        </div>
    </g:hasErrors>


    Nombre: <g:textField name="nombre" value="${fieldValue(bean: command1, field: "nombre")}"/><br/>
    Apellido: <g:textField name="apellido" value="${fieldValue(bean: command1, field: "apellido")}"/><br/>

    <g:submitButton name="enviar"/>
</g:form>
```

# FAQ

### ¿Cuando se valida un constraint de una propiedad y se utiliza `_this`, ya vienen rellenas todas las propiedades?

Si, todas las propiedades vienen rellenas, en esta etapa no se hace binding para pensar si vienen o no llenas, esta es una etapa de validación y por lo tanto se encuentran todos los valores puestos en las propiedades.


### ¿Cómo obtengo el valor antiguo de una propiedad?

```
class Persona {
    String nombre
    String apellido

    static constraints = {
        nombre validator: {value,_this->
            def oldValue = _this.getPersistentValue('nombre')
        }
        apellido validator: {value,_this->
            def oldValue = _this.getPersistentValue('apellido')
        }
    }
}
```


### ¿Cuando se escribe un constraint, se sobreescriben los constraints por default?

El único constraint por default es `nullable:false` y la única manera de sobreescribirlo es sobreescribiendo la propiedad `nullable`. Por lo tanto si se agrega un `validator` personalizado, se mantendrá el constraint `nullable:false`.

### ¿Cómo evitar que el argumento enviado se formatee como un integer y venga separado con comas ?

```
return ["mantosAcelerables.more1abono", String.valueOf(manto.year)]
```


# Referencia

http://docs.grails.org/2.5.x/ref/Constraints/validator.html
<!-- ------------------------------------ -->
<!-- Mostrar errores -->
<!-- ------------------------------------ -->
<g:hasErrors bean="${bean}">
    <div class="alert alert-danger">
        <g:renderErrors bean="${bean}" as="list"/>
    </div>
</g:hasErrors>

以上是关于html Grails约束[验证]的主要内容,如果未能解决你的问题,请参考以下文章

Grails - 从自定义验证器闭包调用内置约束

Grails 使用 Spring Security Core Plugin 测试用户角色自定义验证约束

升级后 Grails 验证不起作用

Grails:将自定义约束应用于域类的所有字段

是否可以在 Grails 之外使用 Grails 验证?如何?

Grails 客户端验证