5

Ho un modulo per creare un luogo. A seconda del paese, il campo provincia (stato, regione) è richiesto o meno.Convalida nullable condizionale o validatore personalizzato con opzione nullable

Quando non è necessario, voglio essere null, non stringa vuota. Ho codice che rende tutti i campi modulo vuoti, null:

def newparams = [:] 
     place = new Place() 
     params.each() { k, v -> 
      if (v instanceof String && place.hasProperty(k)) { 
       if (!v.trim().length()) { 
        newparams[k] = null 
       } else { 
        newparams[k] = v 
       } 
      } 
     } 

     place = new Place(newparams) 
     place.validate() 

Ora, nel dominio posto, ho un validatore sulla provincia:

province validator: {val, obj -> if (obj.country in obj.requiresRegionCountries() && !obj.province) return [province.required]} 

Con questa regola, ho sempre arrivare "provincia non può essere nullo "anche se è richiesto o meno.

Penso che questo sia dovuto al validatore nullable impostato su falso.

Se sto aggiungendo annullabile: vero, allora anche se è richiesto provincia, il validatore personalizzato viene saltato ed è possibile salvare con la provincia di vuoto (credo che sia perché viene istanziato con null)

Ora , ho bisogno di qualche modo il mio validatore personalizzato e anche possibilità di specificare il nullable nel mio validatore, qualcosa di simile:

province validator: {val, obj -> 
    if (obj.country in obj.requiresRegionCountries() && !obj.province) { 
    nullable: false 
    return [province.required] } 
    else { 
    nullable: true 
    } 
} 

Come posso raggiungere questo obiettivo in Grails 2.0.3?

risposta

4

Non posso dire con il codice che hai incollato ma se il tuo problema è che la convalida di default non permette la provincia di essere nulla, hai provato esplicitamente a permettere che la provincia sia nullo? Sono ammessi più validatori per ogni campo. Quindi, di nuovo nel codice originale, basta specificare il validatore annullabile così:

province nullable: true, validator: {val, obj -> 
    if (obj != null && obj.country in obj.requiresRegionCountries() && !obj.province) 
    return [province.required] 
} 

EDIT: Nel validatore personalizzato, potrebbe anche voler evitare l'obj essere nullo nel caso condizione.

EDIT2: Progetto Demo mostra la convalida sopra lavorare su Grails 2.0.4

class Place { 
String country 
Province province 

    static constraints = { 
    province (nullable: true, validator: {val, obj -> 
     if (obj.country == 'Canada' && !val) return ['province.required'] 
    }) 
    } 
} 

controller ...

class MainController { 
    def index() { 
    def place = new Place(country: 'Canada') 
    if (!place.validate()) { 
     render "need province<br/>" + place.errors 
    } else { 
     render "cool" 
    } 

Così l'idea è che ho un controller fittizio dove posso invocare l'azione dell'indice che è hardcoded per creare un'istanza di dominio Place simile al tuo esempio. Si noti che ho definito solo la stringa del paese in modo da poter digitare la logica su quella per la convalida personalizzata. Non ho definito la provincia durante la creazione dell'istanza di Place, quindi dovrebbe essere nullo. In base a tale scenario, la pagina di risposta verrà stampata la seguente ...

frammento di uscita ...

need province 
grails.validation.ValidationErrors: 1 .... does not pass custom validation] 

Se rimuovo l'annullabile: vero vincolo da Place, allora l'errore è il valore nullo come previsto ...

frammento di uscita ...

need province 
grails.validation.ValidationErrors: 1 .... cannot be null] 
+0

Grazie per la risposta, ma c'è un problema. Se imposto di essere nullable e place.province è null, la convalida personalizzata viene completamente ignorata. Voglio essere annullabile per alcuni paesi ma non negli altri. – Eduard

+0

Per essere chiari: se non inserisco nullable true e il file è nullo, l'errore "Can not be null" è trown e il mio validatore personalizzato non viene eseguito. Se aggiungo nullable: true e il valore è null, la convalida passerà, il mio validatore personalizzato non verrà eseguito. Voglio essere nullo per alcuni paesi e non nullo per gli altri. Questo è qualcosa che non posso fare con il comportamento attuale. – Eduard

+0

Forse è un errore Grails 2.0.3. Sono in esecuzione 2.0.4 e funziona per me con un semplice progetto demo che ho creato che incollerò alla mia risposta sopra in modo da poter confrontare – Tri

12

Dopo un sacco di ricerca e di feedback che ho scoperto 2 soluzioni che stanno lavorando. Uno è in controller.Non aggiungere alcuna convalida nel modello e aggiungerli in modo dinamico dal controllore:

class PlacesController { 
    def create() { 
    def place = new Place(params.address) 
    if (place.country in placesThatRequiresProvinceArray) { 
     place.constrains.province.nullable = false 
    } else { 
     place.constrains.province.nullable = true 
    } 

}

L'altra soluzione è quella proposta da Tri in questa discussione, ma mettere il validatore personalizzato prima il vincolo annullabile (altro il validatore personalizzato non verrà chiamato per valori null):

static constraints = { 
    province (validator: {val, obj -> 
    if (obj.country == 'Canada' && !val) 
     return ['province.required'] 
    }, nullable: true) 
}