views:

300

answers:

1

I call a service that creates a parent and a child record. If an error happens, the service throws a RuntimeException. The RuntimeExceptionis is caught by the controller and then there there is a redirect back to the gsp. But the error is not being rendered.

In this case, I guess the controller and thus the gsp doesn't really no anything about the objects, since everything is done in the service. So how do I render the errors?

Simple Data Entry GSP

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Sample title</title>
  </head>
  <body>
    <h1>Add A Record</h1>

<g:hasErrors bean="${parent}">
    <div class="errors">
        <g:renderErrors bean="${parent}" as="list" />
    </div>
</g:hasErrors>
<g:hasErrors bean="${child}">
    <div class="errors">
        <g:renderErrors bean="${child}" as="list" />
    </div>
</g:hasErrors>  
  <g:form action="add" name="doAdd">
    <table>
      <tr>
        <td>
          Parent Name
        </td>
        <td>
          Child Name
        </td>
      </tr>
      <tr>
        <td>
      <g:textField name="parentName"  />
      </td>
      <td>
      <g:textField name="childName" />
      </td>
      </tr>
      <tr><td><g:submitButton name="update" value="Update" /></td></tr>
    </table>
  </g:form>
</body>
</html>

Controller

   class AddrecordController {

    def addRecordsService

    def index = {
        redirect action:"show", params:params
    }

    def add = {
        println "do add"


        try {
            addRecordsService.addAll(params)
        } catch (java.lang.RuntimeException re){
           println re.message
            flash.message = re.message
        }
        redirect action:"show", params:params

    }

    def show = {}

}

Service

  class AddRecordsService {

    static transactional = true



    def addAll(params) {
        def Parent theParent =  addParent(params.parentName)
        def Child theChild  = addChild(params.childName,theParent)
    }

    def addParent(pName) {
        def theParent = new Parent(name:pName)
        if(!theParent.save()){
            throw new RuntimeException('unable to save parent')
        }

        return theParent
    }

    def addChild(cName,Parent theParent) {
        def theChild = new Child(name:cName,parent:theParent)

        if(!theChild.save()){
            throw new RuntimeException('unable to save child')
        } 
        return theChild
    }

}
A: 

You need to get a reference to the invalid object somehow and pass it to the view via the model so I would extend RuntimeException and add fields to contain the objects with validation errors e.g.

}catch(MyCustomException m){
render view:'show', model:[parent:m.getParent(), child:m.getChild()]
}

This whole exercise might be easier using Parent.withTransaction instead of the automatic rollback via RuntimeExceptions. Then you could manually rollback the transaction if there's validation errors and just return the objects instead of having to contain them in the exception.

leebutts