Search code examples
grailsgrails-controller

Grails: render a page in beforeInterceptor


In one of my controllers, I've written some error checking code in the beforeInterceptor closure.

 if (getUser()?.courses?.size() == 0) {
        render(view: '/base/errorMessage', model: [errorMessage: "You don't have any courses!"]);
        return false;
 }

That render call shows a nice, program-wide error page.

However, if I return false, nothing gets displayed! If I return true, the error page shows up just fine, but the action executes anyway (it doesn't get rendered, but the logic still gets executed). This requires duplicate error checking, defeating the purpose of the interceptor.

redirect() calls still work fine, but moving the error display to a different action is messy. Instead of /app/courses, the user would see /app/error/errorMessage in their URL, and it's possible to go right to the error page directly. Then there's the question of getting the message to that action - flash.message? session.var?

Is there a better way?


Solution

  • I know this is a few years old but I think the question is still relevant.

    Grails has provided a more convenient way to validate form input and return flash error messages by using Command Objects and i18n message.properties.

    Essentially, you don't need to write an interceptor. You create a command object in your controller with all the form fields you expect to get when submitted. Then create validation constraints for each field and create your i18n messages for constraint violation errors.

    Now, when you define a controller action and insert the command object as a parameter:

    def someAction(MyCommandObject command) {}
    

    The command object parameter acts somewhat like a beforeInterceptor, in that Grails automatically binds data from the form submit to matching attributes of the command object -- but wait! That's not all! Grails also applies the constraints to the data from the form and essentially runs command.validate() all BEFORE any code is executed in the action. That's why it is a good, and common practice to check your command object instance for errors before you execute any other code in your action, like so:

    def someAction(MyCommandObject command) {
        if(command.hasErrors()){
            //do something -- set flash message error and redirect, etc.
        }
        //other importand code follows ...
    }
    

    I hope this helps others who may find this question relevant. This is just one example of how useful and powerful command objects can be.