5

I'd like to know how to add a custom error to the hasErrors method so that the gsp picks up the error. My code thus far.

def recoverySetup = new RecoverySetup(params)

def onesolOrgkey = OnesolOrgkeyInfo.get(new OnesolOrgkeyInfo(params));

if(onesolOrgkey != null) {
    recoverySetup.setOneSolOrgkey(onesolOrgkey)
} else {
    recoverySetup.errors.reject('orgkey', 'You must provide a valid Org Key')
}

recoverySetup.validate()

if(recoverySetup.hasErrors()) {
    render view: 'create', model: [recoverySetupInstance: recoverySetup]
    return
}
Code Junkie
  • 7,602
  • 26
  • 79
  • 141
  • why not put a custom validator rule on the RecoverySetup domain object? – Nathan Hughes Jul 30 '15 at 19:35
  • There is a database query that checks to see of onesolOrgKey is null. I'm not sure how'd id do that in the domain object. – Code Junkie Jul 30 '15 at 19:42
  • Instead of using the actual domainObject, you could imitate it in your src folder and set all that happen to the bean and part of its validation like: return errors.rejectValue(propertyName,"invalid.$propertyName",[''] as Object[],'') https://github.com/vahidhedayati/grails-bean-validation-examples/blob/master/src/groovy/testing/U2Bean.groovy#L19 where propertyName in the validation bean is field Name that it will represent in the gsp and then you need to match it via the gsp checks – V H Jul 30 '15 at 19:48
  • My apology, but I'm very new to grails and I'm not following you. – Code Junkie Jul 30 '15 at 19:51
  • http://stackoverflow.com/questions/14038905/how-do-i-create-a-custom-validator-with-a-custom-error-message-in-grails might be of help, you need both the gsp elements and your controller/validation method to bind up fields – V H Jul 30 '15 at 20:34

3 Answers3

7

As Danilo says, you probably want to add a constraint to your domain class to do that for you.

Learn more about constraints in http://grails.github.io/grails-doc/2.2.x/guide/single.html#constraints and http://grails.github.io/grails-doc/2.2.x/ref/Constraints/Usage.html .

If for whatever reason you really want to add a custom error that cannot be covered by the constraints (I can't imagine a case right now, but that doesn't mean it doesn't exists :-), you can still do it in a very similar fashion of what you posted:

instance.errors.rejectValue(fieldName, errorCode, message, defaultMessage)
instance.errors.reject(errorCode, message, defaultMessage)

The first rejects a concrete field, the second the bean in general. But bear in mind this errors will be reset when you invoke validate again.

Also, you can display the errors of a bean automatically in grails with:

<g:hasErrors bean="${instance}">
   <g:renderErrors bean="${instance}" />
</g:hasErrors>

See all the options here: https://grails.github.io/grails-doc/2.2.x/ref/Tags/hasErrors.html

Deigote
  • 1,721
  • 14
  • 15
  • 1
    I would only add to that : instance.errors.reject(errorCode, message, defaultMessage) where message is your objects bound to error code.. so instance.errors.reject('invalid.date.range.error', [date1,date2] as Object[], "Date range ${date1} - ${date2} is inavlid"). This will now look for invalid.date.range.error=Invalid input {0} {1} dates invalid.. or something in messages.properties – V H Nov 17 '15 at 15:05
2

Your domain class could look something like this:

class RecoverySetup {
    String someField
    static hasOne = [oneSolOrgkey: OneSolOrgkey]

    static constraints = {
        oneSolOrgkey nullable: false
    }
}

This way you declare that every instance of RecoverySetup is valid only if oneSolOrgkey is defined.

Once you have an instance of RecoverySetup you can check if it is valid by invoking the validate() method which returns a boolean:

if (recoverySetupInstance.validate()) {
    // do something with a valid object
}
else {
    recoverySetupInstance.errors.allErrors.each {err ->
        println err // Print errors
    }
}

if you pass the instance to a view, you will have all errors available in recoverySetupInstance.errors and you can display errors as you prefer.

Danilo
  • 2,676
  • 7
  • 32
  • 36
0

Your question I'd like to know how to add a custom error to the hasErrors method so that the gsp picks up the error is a bit closed, in that it specifically mentions the hasErrors as the way you want to do it.

Another, much simpler, approach is to just create a flash message in your controller before you return to the gsp

flash.error = 'You must provide a valid Org Key'
render view: 'create', model: [recoverySetupInstance: recoverySetup]
return

Then in your gsp, a block to show that flash.error ...

<g:if test="${flash.error}">
<div class="errors" role="status">${flash.error}</div>
</g:if>

This works nicely for those business rule validations that you don't necessarily want to build into your objects, e.g. I used this when I wanted to prevent users accidentally adding duplicates, to a table that could allow duplicates in other cases.

nby
  • 119
  • 1
  • 3
  • 1
    The downside of this approach is that it prevents further validation and only informs about this one error. Adding an error message to object.errors would allow to inform the user about all validation errors at once. – SebastianH Oct 09 '20 at 13:54