Grails domain validator with exception
In this article, I will explains how we can improve the validation flow provided by grails.
Usual pattern
When using default grails scaffolding a controller action, for example save, will look some thing like this :
def save = { def fooInstance = new Foo(params) if(!fooInstance.hasErrors() && fooInstance.save()) { flash.message = "Foo ${fooInstance.id} created" redirect(action:show,id:fooInstance.id) }else { render(view:'create',model:[fooInstance:fooInstance]) } }
Runtime Exceptions in a service cause the transaction to be rolled back, which is the desired behavior when a validation error has occurred.
Service
class FooService { boolean transactional = true Foo saveFoo(Map params) { def fooInstance = new Foo(params) if (!fooInstance.hasErrors() && fooInstance.save()) { return fooInstance } else { throw new ValidationException("Foo is not Valid", fooInstance) } } }
Tip: If you are using grails 1.2 support for this is built into the framework You can now call save(failOnError:true) and and exception will be thrown. Or better yet you can set the configuration parameter grails.gorm.save.failOnError = true to enable in your entire application.
Controller
class FooController { def fooService def save = { try { def fooInstance = fooService.saveFoo(params) redirect(action: show, id: fooInstance.id) } catch (ValidationException e) { log.warn("Validation Failed on Foo ${e.message}" ) render(view: 'create', model: [fooInstance: e.invalidObject]) } } }
Validation Exception
class ValidationException extends RuntimeException { Object invalidObject ValidationException(String message, Object invalidObject){ super(message) this.invalidObject = invalidObject } }
Source: http://keithsgrailstips.blogspot.com/2010/02/use-exceptions-to-control-validation.html