Search

Dark theme | Light theme
Showing posts with label GrailsGoodness:Controllers. Show all posts
Showing posts with label GrailsGoodness:Controllers. Show all posts

July 9, 2014

Grails Goodness: Custom Controller Class with Resource Annotation

In Grails we can apply the @Resource AST (Abstract Syntax Tree) annotation to a domain class. Grails will generate a complete new controller which by default extends grails.rest.RestfulController. We can use our own controller class that will be extended by the @Resource transformation. For example we might want to disable the delete action, but still want to use the @Resource transformation. We simply write a new RestfulController implementation and use the superClass attribute for the annotation to assign our custom controller as the value.

First we write a new RestfulController and we override the delete action. We return a HTTP status code 405 Method not allowed:

// File: grails-app/controllers/com/mrhaki/grails/NonDeleteRestfulController.groovy
package com.mrhaki.grails

import grails.rest.*

import static org.springframework.http.HttpStatus.METHOD_NOT_ALLOWED

/**
 * Custom RestfulController where we disable the delete action.
 */
class NonDeleteRestfulController<T> extends RestfulController<T> {

    // We need to provide the constructors, so the 
    // Resource transformation works.
    NonDeleteRestfulController(Class<T> domainClass) {
        this(domainClass, false)
    }

    NonDeleteRestfulController(Class<T> domainClass, boolean readOnly) {
        super(domainClass, readOnly)
    }

    @Override
    def delete() {
        // Return Method not allowed HTTP status code.
        render status: METHOD_NOT_ALLOWED
    }
    
}

Next we indicate in the @Resource annotation with the superClass attribute that we want to use the NonDeleteRestfulController:

// File: grails-app/domain/com/mrhaki/grails/User.groovy
package com.mrhaki.grails

import grails.rest.*

@Resource(uri = '/users', superClass = NonDeleteRestfulController)
class User {

    String username
    String lastname
    String firstname
    String email

    static constraints = {
        email email: true
        lastname nullable: true
        firstname nullable: true
    }

}

When we access the resource /users/{id} with the HTTP DELETE method we get a 405 Method Not Allowed response status code.

Written with Grails 2.4.2.

Grails Goodness: Change Response Formats in RestfulController

We can write a RESTful application with Grails and define our API in different ways. One of them is to subclass the grails.rest.RestfulController. The RestfulController already contains a lot of useful methods to work with resources. For example all CRUD methods (save/show/update/delete) are available and are mapped to the correct HTTP verbs using a URL mapping with the resource(s) attribute.

We can define which content types are supported with the static variable responseFormats in our controller. The variable should be a list of String values with the supported formats. The list of supported formats applies to all methods in our controller. The names of the formats are defined in the configuration property grails.mime.types. We can also use a Map notation with the supportedFormats variable. The key of the map is the method name and the value is a list of formats.

// File: grails-app/controllers/com/mrhaki/grails/UserApiController.groovy
package com.mrhaki.grails

import grails.rest.*

class UserApiController extends RestfulController {

    // Use Map notation to set supported formats
    // per action.
    static responseFormats = [
        index: ['xml', 'json'],  // Support both XML, JSON
        show: ['json']           // Only support JSON
    ]

    // We make the resource read-only in
    // the constructor.
    UserApiController() {
        super(User, true /* read-only */)
    }

}

We can also specify supported formats per action using the respond method in our controller. We can define the named argument formats followed by a list of formats when we invoke the respond method. In the following controller we override the index and show methods and use the formats attribute when we use the respond method:

// File: grails-app/controllers/com/mrhaki/grails/UserApiController.groovy
package com.mrhaki.grails

import grails.rest.*

class UserApiController extends RestfulController {

    // We make the resource read-only in
    // the constructor.
    UserApiController() {
        super(User, true /* read-only */)
    }

    @Override
    def index(Integer max) {
        params.max = Math.min(max ?: 10, 100)
        respond listAllResources(params), formats: ['xml', 'json']
    }

    @Override
    def show() {
        respond queryForResource(params.id), formats: ['json']
    }

}

Code written with Grails 2.4.2.

May 23, 2014

Grails Goodness: Exception Methods in Controllers

Since Grails 2.3 we can define exception methods in our controllers to handle exceptions raised by code invoked in the action methods of the controllers. Normally we would write a try/catch statement to handle an exception or let it continue up the stack until a 500 error page is shown. But with exception methods we can write code to handle exceptions in a controller without a try/catch statement. An exception method should define the type of exception it handles as the method argument. We can have multiple exception methods for different exception types. Also subclasses of a controller will use the exception methods if applicable.

In the following controller we have a couple of action methods: index and show. And we have two exception methods: connectException and notFoundException. The connectException method has a single argument of type ConnectException. This means that any code in the controller that will raise a ConnectException will be handled by this method. And any ResourceNotFoundException thrown in the controller will be handled by the notFoundException method, because the argument type is ResourceNotFoundException.

package com.mrhaki.grails

class SampleController {

    /**
     * Service with methods that are invoked
     * from the controller action methods.
     */ 
    ExternalService externalService

    //--------------------------------------------
    // Action methods:
    //--------------------------------------------

    /** Index action method */
    def index() { 

        // These method calls could throw a ConnectException.
        // If the ConnectException occurs then the 
        // connectException(ConnectException) method is
        // invoked and that method will handle the 
        // request further.
        final all = externalService.all(params)
        final total = externalService.count()
        
        [items: all, totalCount: total]
    }

    /** Show action method */
    def show(final Long id) {

        // This method can throw a ConnectException
        // or ResourceNotFoundException. 
        // If the ResourceNotFoundException is thrown
        // the request is further handled by 
        // the notFoundException(ResourceNotFoundException)
        // method.
        final item = externalService.get(id)
        [item: item]
    }


    //--------------------------------------------
    // Exception methods:
    //--------------------------------------------

    /**
     * If any method in this controller invokes code that
     * will throw a ConnectException then this method
     * is invoked.
     */
    def connectException(final ConnectException exception) {
        logException exception
        render view: 'error', model: [exception: exception]
    }

    /**
     * If any method in this controller invokes code that
     * will throw a ResourceNotFoundException then this method
     * is invoked.
     */
    def notFoundException(final ResourceNotFoundException exception) {
        logException exception
        render view: 'notFound',  model: [id: params.id, exception: exception]        
    }


    /** Log exception */
    private void logException(final Exception exception) {
        log.error "Exception occurred. ${exception?.message}", exception
    }

}

Code written with Grails 2.4.0.

December 9, 2013

Grails Goodness: Using Closures for Select Value Rendering

To generate an HTML select we can use the Grails tag <g:select .../>. We use the optionValue attribute to specify a specific property we want to be used as the value. But we can also define a closure for the optionValue attribute to further customize the value that is shown to the user.

Suppose we have a simple domain class Book with a couple of properties. We want to combine multiple properties as the text for the HTML select options. In the following GSP we define first a <g:select .../> tag where we simply use the title property. In the next <g:select .../> tag we use a closure to combine multiple properties.

We can also pass the closure as model property to the GSP from a controller. In a controller we define the transformation in a closure and pass it along to the GSP page. On the GSP we can use this closure as a value for the optionValue attribute of the <g:select .../> tag. The following GSP shows all three scenarios.

<%@ page import="com.mrhaki.grails.sample.Book" contentType="text/html;charset=UTF-8" %>
<html>
<head>
    <title>Simple GSP page</title>
    <meta name="layout" content="main"/>
    <style>
        p { margin-top: 20px; margin-bottom: 5px;}
    </style>
</head>

<body>

    <h1>Select</h1>

    <p>Use title property of book for option values</p>

    <g:select from="${Book.list()}"
          optionKey="id"
          optionValue="title"
          name="bookSimple"/>

    <p>Use closure for optionValue</p>
    <g:select from="${Book.list()}"
              optionKey="id"
              optionValue="${{ book -> "${book.title} - ${book.isbn}" }}"
              name="bookCustom"/>

    <g:set var="bookOptionValueFormatter"
           value="${{ book -> "${book.title} (${book.isbn}, ${book.numberOfPages})" }}"/>

    <p>Use bookOptionValueFormatter that is defined as variable on this page</p>
    <g:select from="${Book.list()}"
              optionKey="id"
              optionValue="${bookOptionValueFormatter}"
              name="bookVar"/>

    <p>Use bookFormatter that is passed as a model property from SampleController.</p>
    <g:select from="${Book.list()}"
              optionKey="id"
              optionValue="${bookFormatter}"
              name="bookModel"/>

</body>


</html>

Here is a sample controller which passes the transformation to the GSP:

package com.mrhaki.grails.sample

class SampleController {

    def index() {
        final formatter = { book -> "$book.title (pages: $book.numberOfPages)" }
        [bookFormatter: formatter]
    }
}

When we run the application and open the page in a web browser we get the following HTML source:

...
<h1>Select</h1>

<p>Use title property of book for option values</p>

<select name="bookSimple" id="bookSimple" >
  <option value="1" >It</option>
  <option value="2" >The Stand</option>
</select>

<p>Use closure for optionValue</p>
<select name="bookVar" id="bookCustom" >
  <option value="1" >It - 0451169514</option>
  <option value="2" >The Stand - 0307743683</option>
</select>

<p>Use bookOptionValueFormatter that is defined as variable on this page</p>
<select name="bookVar" id="bookVar" >
  <option value="1" >It (0451169514, 1104)</option>
  <option value="2" >The Stand (0307743683, 1472)</option>
</select>

<p>Use bookFormatter that is passed as a model property from SampleController.</p>
<select name="bookModel" id="bookModel" >
  <option value="1" >It (pages: 1104)</option>
  <option value="2" >The Stand (pages: 1472)</option>
</select>
...

The optionKey attribute also allows closures as arguments.

Code written with Grails 2.3.2.

November 19, 2013

Grails Goodness: Get Request Parameters with Default Values

In Grails we can convert a request parameter to a type directly. We must then use the int(), short(), byte(), long(), double(), float(), boolean() or list() methods that are added to the params object available in our controllers.

Since Grails 2.3 we can also pass a default value, which is used when the request parameter is not set. In the following controller we use the double() method and define a default value of 42.0.

// File: grails-app/controllers/com/mrhaki/grails/SampleController.groovy
package com.mrhaki.grails

class SampleController {

    def index() {
        // Get request parameter named v.
        // Use default value 42.0 if not set.
        final double value = params.double('v', 42.0)
        [value: value]
    }

}

The following test shows that the default value is returned if the request parameter is not set, otherwise the value of the request parameter is returned:

// File: test/unit/com/mrhaki/grails/SampleControllerSpec.groovy
package com.mrhaki.grails

import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(SampleController)
class SampleControllerSpec extends Specification {

    def "request parameter v must return default value if not set"() {
        expect:
        controller.index().value == 42.0
    }

    def "request parameter v must return value set"() {
        given:
        params.v = '10.1'

        expect:
        controller.index().value == 10.1
    }

}

We can use the same methods now also to get attribute values in a tag library. So we can do a type conversion and provide a default value if we want to. In the following tag library we use this in the tag sample:

// File: grails-app/taglib/com/mrhaki/grails/SampleTagLib.groovy
package com.mrhaki.grails

class SampleTagLib {

    static namespace = 'sample'

    static returnObjectForTags = ['sample']

    def sample = { attributes, body ->
        final double value = attributes.double('v', 42.0)
        value
    }
    
}

With the following Spock specification we can see that the default value 42.0 is used if the attribute v is not set. Otherwise the value of the attribute is returned:

// File: test/unit/com/mrhaki/grails/SampleTagLibSpec.groovy
package com.mrhaki.grails

import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(SampleTagLib)
class SampleTagLibSpec extends Specification {

    def "attribute v returns default value if attribute is not set"() {
        expect:
        applyTemplate('<sample:sample/>') == '42.0'
    }

    def "attribute v returns value if attribute v if set"() {
        expect:
        applyTemplate('<sample:sample v="${v}"/>', [v: 10.1]) == '10.1'
    }

}

Code written with Grails 2.3.

November 18, 2013

Grails Goodness: Create Report of URL Mappings

Since Grails 2.3 we can use the url-mappings-report command to get a nice report of the URL mappings we have defined in our application. Also implicit mappings created for example by using the resources attribute on a mapping definition are shown in the report. This report is very useful to see which URLs are exposed by your application and how they map to controllers.

Suppose we have the following grails-app/conf/UrlMappings.groovy with a couple of mappings:

// File: grails-app/conf/UrlMappings.groovy
class UrlMappings {

    static mappings = {
        // Map to HTTP methods.
        "/upload"(controller: 'upload') {
            action = [POST: 'file']
        }

        // RESTful API.
        "/api/users"(resources: 'user')

        // Default mapping.
        "/$controller/$action?/$id?(.${format})?"()

        // Main index.
        "/"(view: "/index")

        // Error mappings.
        "500"(controller: 'error')
        "404"(controller: 'error', action: 'notFound')
    }
}

When we run the following command $ grails url-mappings-report we get the following output:

| URL Mappings Configured for Application
| ---------------------------------------

Dynamic Mappings
 |    *     | /${controller}/${action}?/${id}?(.${format)?              | Action: (default action)      |
 |    *     | /                                                         | View:   /index                |

Controller: dbdoc
 |    *     | /dbdoc/${section}?/${filename}?/${table}?/${column}?      | Action: (default action)      |

Controller: error
 |    *     | ERROR: 500                                                | Action: (default action)      |
 |    *     | ERROR: 404                                                | Action: notFound              |

Controller: upload
 |    *     | /upload                                                   | Action: {POST=file}           |

Controller: user
 |   GET    | /api/users                                                | Action: index                 |
 |   GET    | /api/users/create                                         | Action: create                |
 |   POST   | /api/users                                                | Action: save                  |
 |   GET    | /api/users/${id}                                          | Action: show                  |
 |   GET    | /api/users/${id}/edit                                     | Action: edit                  |
 |   PUT    | /api/users/${id}                                          | Action: update                |
 |  DELETE  | /api/users/${id}                                          | Action: delete                |

Notice also mappings added by plugins like the mappings to dbdoc controller are shown.

Code written with Grails 2.3.

November 15, 2013

Grails Goodness: Namespace Support for Controllers

In a Grails application we can organize our controllers into packages, but if we use the same name for multiple controllers, placed in different packages, then Grails cannot resolve the correct controller name. Grails ignores the package name when finding a controller by name. But with namespace support since Grails 2.3 we can have controllers with the same name, but we can use a namespace property to distinguish between the different controllers.

We can add a new static property to a controller class with the name namespace. The value of this property defines the namespace. We can then write new URL mappings in the grails-app/conf/UrlMappings.groovy file and use the namespace value as a mapping attribute.

Suppose we have two ReportController classes in our application. One is defined as com.mrhaki.grails.user.ReportController and the other as com.mrhaki.grails.common.ReportController. The following code samples show sample implementations for both controllers:

// File: grails-app/controllers/com/mrhaki/grails/user/ReportController.groovy
package com.mrhaki.grails.user

class ReportController {

    /** Namespace is set to user. Used in URLMappings. */
    static namespace = 'user'

    def index() {
        render 'UserReport'
    }
}

And the second controller:

// File: grails-app/controllers/com/mrhaki/grails/common/ReportController.groovy
package com.mrhaki.grails.common

class ReportController {

    /** Namespace is set to common. Used in URLMappings. */
    static namespace = 'common'

    def index() {
        render 'CommonReport'
    }
}

In our UrlMappings.groovy file we can now add two extra mappings for these controllers and we use the new namespace attribute to point the mapping to the correct controller implementation.

// File: grails-app/conf/UrlMappings.groovy
class UrlMappings {

    static mappings = {
        // Define mapping to com.mrhaki.grails.user.ReportController with namespace user.
        "/user-report/$action?/$id?(.${format})?"(controller: 'report', namespace: 'user')

        // Define mapping to com.mrhaki.grails.common.ReportController with namespace common.
        "/common-report/$action?/$id?(.${format})?"(controller: 'report', namespace: 'common')


        // Other mappings.
        "/$controller/$action?/$id?(.${format})?"()
        "/"(view: "/index")
        "500"(view: '/error')
    }
}

The namespace support is also useful in building RESTful APIs with Grails. We can use the namespace attribute to have different versions for the same controller. For example in the following UrlMappings.groovy configuration we have two mappings to a controller with the same name, but the namespace attribute defines different version values:

// File: grails-app/conf/UrlMappings.groovy
class UrlMappings {

    static mappings = {
        // Define mapping to com.mrhaki.grails.api.v1.UserController with namespace v1.
        "/api/v1/users"(resource: 'user', namespace: 'v1')

        // Define mapping to com.mrhaki.grails.api.v2.UserController with namespace v2.
        "/api/v2/users"(resource: 'user', namespace: 'v2')


        // Other mappings.
        "/"(controller: 'apiDoc')
        "500"(controller: 'error')
    }
}

To create links to controllers with a namespace we can use the new namespace attribute in the link and createLink tags. The following GSP page part shows how we can set the namespace so a correct link is generated:

<h2>Links</h2>
<ul>
    <li><g:link controller="report" namespace="user">User Reports</g:link></li>
    <li><g:link controller="report" namespace="common">Common Reports</g:link></li>
    <li><g:createLink controller="report" namespace="user"/></li>
    <li><g:createLink controller="report" namespace="common"/></li>
</ul>

We get the following HTML:

<h2>Links</h2>
<ul>
    <li><a href="/namespace-controller/user-report/index">User Reports</a></li>
    <li><a href="/namespace-controller/common-report/index">Common Reports</a></li>
    <li>/namespace-controller/user-report/index</li>
    <li>/namespace-controller/common-report/index</li>
</ul>

Code written with Grails 2.3.2.

October 13, 2013

Grails Goodness: Add Extra Valid Domains and Authorities for URL Validation

Grails has a built-in URL constraint to check if a String value is a valid URL. We can use the constraint in our code to check for example that the user input http://www.mrhaki.com is valid and http://www.invalid.url is not. The basic URL validation checks the value according to standards RFC1034 and RFC1123. If want to allow other domain names, for example server names found in our internal network, we can add an extra parameter to the URL constraint. We can pass a regular expressions or a list of regular expressions for patterns that we want to allow to pass the validation. This way we can add IP addresses, domain names and even port values that are all considered valid. The regular expression is matched against the so called authority part of the URL. The authority part is a hostname, colon (:) and port number.

In the following sample code we define a simple command object with a String property address. In the constraints block we use the URL constraint. We assign a list of regular expression String values to the URL constraint. Each of the given expressions are valid authorities, we want the validation to be valid. Instead of a list of values we can also assign one value if needed. If we don't want to add extra valid authorities we can simple use the parameter true.

// Sample command object with URL constraint.
class WebAddress {
    String address

    static constraints = {
        address url: ['129.167.0.1:\\d{4}', 'mrhaki'] 

        // Or one String value if only regular expression is necessary: 
        // address url: '129.167.0.1:\\d{4}'

        // Or simple enable URL validation and don't allow
        // extra hostnames or authorities to be valid
        // address url: true
    }
}

Code written with Grails 2.2.4

September 12, 2013

Grails Goodness: Unit Testing Render Templates from Controller

In a previous blog post we learned how we can unit test a template or view independently. But what if we want to unit test a controller that uses the render() method and a template with the template key instead of a view? Normally the view and model are stored in the modelAndView property of the response. We can even use shortcuts in our test code like view and model to check the result. But a render() method invocation with a template key will simply execute the template (also in test code) and the result is put in the response. With the text property of the response we can check the result.

In the following sample controller we use the header template and pass a username model property to render output.

%{-- File: /grails-app/views/sample/_header.gsp --}%
<g:if test="${username}">
    <h1>Hi, ${username}</h1>
</g:if>
<g:else>
    <h1>Welcome</h1>
</g:else>
package com.mrhaki.grails.web

class SampleController {

    def index() {
        render template: 'header', model: [username: params.username]
    }

}

With this Spock specification we test the index() action:

package com.mrhaki.grails.web

import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(SampleController)
class SampleControllerSpec extends Specification {

    def "index action renders template with given username"() {
        given:
        params.username = username

        when:
        controller.index()

        then:
        response.text.trim() == expectedOutput

        where:
        username || expectedOutput
        'mrhaki' || '

Hi, mrhaki

' null || '

Welcome

' } }

Suppose we don't want to test the output of the actual template, but we only want to check in our test code that the correct template name is used and the model is correct. We can use the groovyPages or views properties in our test code to assign mock implementation for templates. The groovyPages or views are added by the ControllerUnitTestMixin class, which is done automatically if we use the @TestFor() annotation. The properties are maps where the keys are template locations and the values are strings with mock implementations for the template. For example the template location for our header template is /sample/_header.gsp. We can assign a mock String implementation with the following statement: views['/sample/_header.gsp'] = 'mock implementation'

We can rewrite the Spock specification and now use mock implementations for the header template. We can even use the model in our mock implementation, so we can check if our model is send correctly to the template.

package com.mrhaki.grails.web

import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(SampleController)
class SampleControllerSpec extends Specification {

    def "index action renders mock template with given username"() {
        given:
        // Mock implementation with escaped $ (\$), because otherwise
        // the String is interpreted by Groovy as GString.
        groovyPages['/sample/_header.gsp'] = "username=\${username ?: 'empty'}"

        // Or we can use views property:
        //views['/sample/_header.gsp'] = "username=\${username ?: 'empty'}"

        and:
        params.username = username

        when:
        controller.index()

        then:
        response.text.trim() == expectedOutput

        where:
        username || expectedOutput
        'mrhaki' || 'username=mrhaki'
        null     || 'username=empty'
    }

}

Code written with Grails 2.2.4

September 5, 2013

Grails Goodness: Render Binary Output with the File Attribute

Since Grails 2 we can render binary output with the render() method and the file attribute. The file attribute can be assigned a byte[], File, InputStream or String value. Grails will try to determine the content type for files, but we can also use the contentType attribute to set the content type.

In the following controller we find an image in our application using grailsResourceLocator. Then we use the render() method and the file and contenType attributes to render the image in a browser:

package com.mrhaki.render

import org.codehaus.groovy.grails.core.io.ResourceLocator
import org.springframework.core.io.Resource

class ImageController {

    ResourceLocator grailsResourceLocator

    def index() {
        final Resource image = grailsResourceLocator.findResourceForURI('/images/grails_logo.png')
        render file: image.inputStream, contentType: 'image/png' 
    }
    
}

The following screenshots shows the output of the index() action in a web browser:



We can use the fileName attribute to set a filename for the binary content. This will also set a response header with the name Content-Disposition with a the filename as value. Most browser will then automatically download the binary content, so it can be saved on disk. Grails will try to find the content type based on the extension of the filename. A map of extensions and content type values is defined in the grails-app/conf/Config.groovy configuration file. We can add for example for png a new key/value pair:

...
grails.mime.types = [
    all:           '*/*',
    png:           'image/png',
    atom:          'application/atom+xml',
    css:           'text/css',
    csv:           'text/csv',
    form:          'application/x-www-form-urlencoded',
    html:          ['text/html','application/xhtml+xml'],
    js:            'text/javascript',
    json:          ['application/json', 'text/json'],
    multipartForm: 'multipart/form-data',
    rss:           'application/rss+xml',
    text:          'text/plain',
    xml:           ['text/xml', 'application/xml']
]
...

In our controller we can change the code so we use the fileName attribute:

package com.mrhaki.render

import org.codehaus.groovy.grails.core.io.ResourceLocator
import org.springframework.core.io.Resource

class ImageController {

    ResourceLocator grailsResourceLocator

    def index() {
        final Resource image = grailsResourceLocator.findResourceForURI('/images/grails_logo.png')
        render file: image.inputStream, fileName: 'logo.png' 
    }
    
}

Code written with Grails 2.2.4

August 19, 2013

Grails Goodness: Set Request Locale in Unit Tests

There is really no excuse to not write unit tests in Grails. The support for writing tests is excellent, also for testing code that has to deal with the locale set in a user's request. For example we could have a controller or taglib that needs to access the locale. In a unit test we can invoke the addPreferredLocale() method on the mocked request object and assign a locale. The code under test uses the custom locale we set via this method.

In the following controller we create a NumberFormat object based on the locale in the request.

package com.mrhaki.grails

import java.text.NumberFormat

class SampleController {

    def index() {
        final Float number = params.float('number')
        final NumberFormat formatter = NumberFormat.getInstance(request.locale)
        render formatter.format(number)
    }

}

If we write a unit test we must use the method addPreferredLocale() to simulate the locale set in the request. In the following unit test (written with Spock) we use this method to invoke the index() action of the SampleController:

package com.mrhaki.grails

import grails.test.mixin.TestFor
import spock.lang.Specification
import spock.lang.Unroll

@TestFor(SampleController)
class SampleControllerSpec extends Specification {

    @Unroll
    def "index must render formatted number for request locale #locale"() {
        given: 'Set parameter number with value 42.102'
        params.number = '42.102'

        and: 'Simulate locale in request'
        request.addPreferredLocale locale

        when: 'Invoke controller action'
        controller.index()

        then: 'Check response equals expected result'
        response.text == result

        where:
        locale           || result
        Locale.US        || '42.102'
        new Locale('nl') || '42,102'
        Locale.UK        || '42.102'
    }

}

Code written with Grails 2.2.4

August 14, 2013

Grails Goodness: Using the header Method to Set Response Headers

Grails adds a couple of methods and properties to our controller classes automatically. One of the methods is the header() method. With this method we can set a response header with a name and value. The methods accepts two arguments: the first argument is the header name and the second argument is the header value.

In the following controller we invoke the header() method to set the header X-Powered-By with the Grails and Groovy version.

package header.ctrl

class SampleController {

    def grailsApplication

    def index() {
        final String grailsVersion = grailsApplication.metadata.getGrailsVersion()
        final String groovyVersion = GroovySystem.version
        header 'X-Powered-By', "Grails: $grailsVersion, Groovy: $groovyVersion"
    }

}

We can test this with the following Spock specification:

package header.ctrl

import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(SampleController)
class SampleControllerSpec extends Specification {

    def "index must set response header X-Powered-By with value"() {
        when:
        controller.index()

        then:
        response.headerNames.contains 'X-Powered-By'
        response.header('X-Powered-By') == 'Grails: 2.2.4, Groovy: 2.0.8'
    }

}

Code written with Grails 2.2.4

February 27, 2012

Grails Goodness: Binding Method Arguments in Controller Methods

Since Grails 2.0 we can use methods instead of closures to define actions for our controllers. We already could pass a command object to a method as argument, but we can also use primitive typed arguments in our method definition. The name of the argument is the name of the request parameter we pass to the controller. Grails will automatically convert the request parameter to the type we have used in our method definition. If the type conversion fails then the parameter will be null.

Let's create a method in a controller with three arguments: a String typed argument with the names author and book. And an argument with type Long with the name id.

// File: grails-app/controllers/sample/MethodSampleController.groovy
package sample

class MethodSampleController {
    /**
     * Sample method with 3 arguments.
     *
     * @param author Name of author
     * @param id Identifier for author
     * @param book Book title 
     */
    def sample(final String author, final Long id, final String book) {
        render "Params: author = $author, book= $book, id = $id"
    }

}

If we invoke our controller with http://localhost:8080/grails-samples/methodSample/sample?id=100&book=It&author=Stephen%20King we get the following output:

Params: name= Stephen King, book = It, id = 100

Suppose we don't provide a valid long value for the id parameter we see in the output id is null. We use the following URL http://localhost:8080/grails-samples/methodSample/sample?id=1a&book=The%20Stand&author=Stephen%20King.

Params: author = Stephen King, book = The Stand, id = null

After reading this blog post and looking at the Grails documentation I learned we can even change the name of the argument and map it to a request parameter name with the @RequestParameter annotation. So then the name of the argument and the request parameter don't have to be the same.

Let's change our sample method and see what the output is:

// File: grails-app/controllers/sample/MethodSampleController.groovy
package sample

import grails.web.RequestParameter

class MethodSampleController {
    /**
     * Sample method with 3 arguments.
     *
     * @param author Name of author
     * @param id Identifier for author
     * @param book Book title 
     */
    def sample(final String author, @RequestParameter('identifier') final Long id, @RequestParameter('bookTitle') final String book) {
        render "Params: author = $author, book = $book, id = $id"
    }

}

Now we need the following URL to see correct output: http://localhost:8080/controllers/author/sample?bookTitle=It&identifier=200&author=Stephen%20King.

Params: name= Stephen King, book = It, id = 200

January 11, 2012

Grails Goodness: Date Request Parameter Value Conversions

Grails has great support for type conversion on request parameters. And since Grails 2.0 the support has been extended to include dates. In our controller we can use the date() method on the params object to get a date value. The value of a request parameter is a String, so the String value is parsed to a Date object.

The default expected date format is yyyy-MM-dd HH:mm:ss.S. If we don't specify a specific date format in the date() method then this format is used. Or we can add a format to our messages.properties with the key date.<param-name>.format. Grails will first try the default format, but if the request parameter cannot be parsed to a valid Date object then Grails will do a lookup of the date format in messages.properties. Technically Grails uses the MessageSource bean to get the format, so we even can define the format per language or country.

Alternatively we can pass a date format or multiple date formats to the date() method. Grails will use these date formats to parse the request parameter into a valid Date object.

Let's show the different options we have in a simple sample controller:

// File: grails-app/controllers/param/date/SampleController.groovy
package param.date

class SampleController {

    final def dateFormats = ['yyyy-MM-dd', 'yyyyMMdd']

    def index() {
        [
                defaultFormatDate: defaultFormatDate,
                defaultFormatNameDate: defaultFormatNameDate,
                singleFormatDate: singleFormatDate,
                multipleFormatsDate1: multipleFormatsDate1,
                multipleFormatsDate2: multipleFormatsDate2
        ]
    }

    private Date getDefaultFormatDate() {
        // Use default format yyyy-MM-dd HH:mm:ss.S
        params.date 'defaultFormatDate'
    }

    private Date getDefaultFormatNameDate() {
        // Lookup format with key date.defaultFormatNameDate.format
        // in messages.properties: yyyy-MM-dd
        params.date 'defaultFormatNameDate'
    }

    private Date getSingleFormatDate() {
        params.date 'singleFormatDate', 'yyyyMMdd'
    }

    private Date getMultipleFormatsDate1() {
        params.date 'multipleFormatsDate1', dateFormats
    }

    private Date getMultipleFormatsDate2() {
        params.date 'multipleFormatsDate2', dateFormats
    }

}

In messages.properties we define the format for the request parameter defaultFormatNameDate:

# File: grails-app/i18n/messages.properties
...
date.defaultFormatNameDate.format=yyyy-MM-dd
...

To show that the date parsing works we write a little integration test. We need this to be an integration test, because then the lookup of the key via the MessageSource bean works.

package param.date

import org.junit.Test

class SampleControllerTests extends GroovyTestCase {

    @Test
    void testDateParameters() {
        def controller = new SampleController()

        // Set request parameters.
        def params = [
                defaultFormatDate: inputDateTime.format('yyyy-MM-dd HH:mm:ss.S'),
                defaultFormatNameDate: inputDateTime.format('yyyy-MM-dd'),
                singleFormatDate: inputDateTime.format('yyyyMMdd'),
                multipleFormatsDate1: inputDateTime.format('yyyy-MM-dd'),
                multipleFormatsDate2: inputDateTime.format('yyyyMMdd')
        ]
        controller.request.parameters = params

        def model = controller.index()

        assertDates inputDateTime, model.defaultFormatDate
        assertDates inputDate, model.defaultFormatNameDate
        assertDates inputDate, model.singleFormatDate
        assertDates inputDate, model.multipleFormatsDate1
        assertDates inputDate, model.multipleFormatsDate2
    }

    private void assertDates(final Date expected, final Date controllerDate) {
        assertEquals expected.toGMTString(), controllerDate.toGMTString()
    }

    /**
     * Create Date object for January 10, 2012 14:12:01.120
     */
    private Date getInputDateTime() {
        final Calendar cal = Calendar.instance
        cal.updated(year: 2012, month: Calendar.JANUARY, date: 10, 
                    hours: 14, minutes: 12, seconds: 1, milliSeconds: 120)
        cal.time
    }

    private Date getInputDate() {
        final Date inputDateTime = inputDateTime
        inputDateTime.clearTime()
        inputDateTime
    }
}

February 25, 2011

Grails Goodness: Controller Properties as Model

To pass data from a controller to a view we must return a model. The model is a map with all the values we want to show on the Groovy Server Page (GSP). We can explicitly return a model from an action, but if we don't do that the controller's properties are passed as the model to the view. Remember that in Grails a new controller instance is created for each request. So it is save to use the properties of the controller as model in our views.

// File: grails-app/controllers/com/mrhaki/SampleController.groovy
package com.mrhaki

class SampleController {

    def values = ['Grails', 'Groovy', 'Griffon', 'Gradle', 'Spock']

    def greeting

    def index = {
        greeting = 'Welcome to My Blog'
        // Don't return a model, so the properties become the model.
    }
}
<%-- File: grails-app/views/sample/index.gsp --%>
<html>
    <head>
    </head>
    <body>
        <h1>${greeting}</h1>

        <g:join in="${values}"/> rock!
    </body>
</html>

May 6, 2010

Grails Goodness: Use the GSP Template Engine in a Controller

The GSP TemplateEngine used to render the GSP pages in Grails is also available as standalone service in for example our controllers, taglibs or services. In the Spring application context the template engine is loaded with the name groovyPagesTemplateEngine. This means we only have to define a new variable in our controller with this name and the Spring autowire by name functionality will automatically insert the template engine in our class. See the following code sample where we use the template engine, notice we even can use taglibs in our template code.

package com.mrhaki.grails

class SimpleController {
    def groovyPagesTemplateEngine
    
    def index = {
        def templateText = '''\
<html>
<body>
<h1>GSP Template Engine</h1>

<p>This is just a sample with template text.</p>

<g:if test="${show}"><p>We can use taglibs in our template!</p></g:if>

<ul>
<g:each in="${items}" var="item">
    <li>${item}</li>
</g:each>
</ul>
</body>
</html>
        '''
        
        def output = new StringWriter()
        groovyPagesTemplateEngine.createTemplate(templateText, 'sample').make([show: true, items: ['Grails','Groovy']]).writeTo(output)
        render output.toString()
    }
}

We get the following HTML output:

<html>
<body>
<h1>GSP Template Engine</h1>

<p>This is just a sample with template text.</p>

<p>We can use taglibs in our template!</p>

<ul>

    <li>Grails</li>

    <li>Groovy</li>

</ul>
</body>
</html>

July 28, 2009

Grails Goodness: Change Scaffolding Templates in Grails

The scaffolding feature in Grails is impressive, especially when we want to show off Grails to other developers. Seems like magic is happening with only a minimal of code. But what if we don't like the default pages Grails generates for us. Of course there is a way to have another layout for the dynamically generated pages.

First we start with a simple, one domain object application:

$ grails create-app scaffold-sample
$ cd scaffold-sample
$ grails create-domain-class message
$ grails create-controller message

We open grails-app/domain/Message.groovy and add the following simple attribute with a small constraint:

class Message {
    String text

    static constraints = {
        text maxLength:140
    }
}

Next we add the magic code to the grails-app/controllers/MessageController.groovy:

class MessageController {
    def scaffold = true
}

We are ready to run the application and we are able to view, add, update or delete messages:

$ grails run-app

We see the default layout we get from Grails. To see which GSP files Grails uses to generate these pages we only have to invoke one command:

$ grails install-templates

After the script is finished we have a new directory src/templates. In this directory we find the scaffolding directory with a couple of GSP files. To change the layout of the pages we only have to make our changes here. Every controller which uses scaffolding will get these changes. Let's create a new CSS file and use it in the create.gsp, edit.gsp, list.gsp and show.gsp files.

We create a new file scaffold.css in the web-app/css directory:

body {
    background-color: #EFE14E;
}
.logo {
    font: 28px bold Georgia;
    color: #006DBA;
    padding: 0.3em;
}
table {
    background-color: #F3EFC9;
}

We open the files create.gsp, edit.gsp, list.gsp and show.gsp and add the following line in the HTML head section:

<link rel="stylesheet" href="\${resource(dir: 'css', file: 'scaffold.css')}"/>

Now when we run the application again we see that the dynamically generated pages are using the new CSS file:

Besides a simple change like this, we can of course do anything we want with the GSP files that are used for scaffolding. In the above screenshot we can see for example we have removed the default Grails logo and replaced it with our own text.