Fork me on GitHub

LD.

Music, software, life… and stuff.

[ Twitter ] [ GitHub ] [ Linked In ]

Painless Page Identification with Geb & Grails

This will be a discussion of a handy pattern to use to make page identification simple and easy when working with Geb and Grails.

Geb and Page Identification

Geb supports (and encourages) using the Page Object Pattern. An aspect of this is having someway of being able to verify that the page object actually does represent the page that the browser is at. Consider filling out a form. When you submit the form you might expect to go to a confirmation page, but because of a validation error you get returned to the form page. In your test code after submitting the form you go on testing for things on the page and the results can be confusing. The best thing to do before testing parts of the page is to test that the page is indeed what you expect it to be. There are other reasons for page identification, but this is the main one.

Geb implements page identification through it’s “at checking”. In short, pages declare an “at” closure that contains some checks of the page structure, and returns true if the actual browser page is what the page object represents.

import geb.*

class ManualPage extends Page {
    static at = { $("h1", text: contains("Manual")) }
}

This “at check” is used implicitly when using the browser at(«PageClass») method…

Browser.driver {
    to ManualPage
    assert at(ManualPage) 
}

The at(«PageClass») method does two things:

  1. Checks the browser’s page object is an instance of the given class
  2. Checks the browser’s page object’s at checker returns true

The use of a Class with the at() method may seem strange. After using Geb for a short amount of time the reasons do become clear. Primarily, your test code is likely to not to declare page changes (such as when content declares a to property). This means that asserting the type of the current page object becomes important.

Writing a good at checker can be hard at times. You want to test enough so that you are sure the page is a match, yet you don’t want to test too much to make your checks fragile.

Grails and Conventions

Fortunately, Grails’ controller/action convention makes identifying pages cost free and definitive (for almost all cases). The trick lies in the controllerName and actionName variables being available in each action’s view implicitly. This allows you to make your Grails GSP templates look something like this…

<html>
<head>
  <meta name="pageId" content="${controllerName}.${actionName}" />
  …
</head>
<body>
  …
</body>
</html>

Every view generated from a controller action in your application now has a unique identifier embedded into the page in an unobtrusive manner.

Action Page Objects

Geb goes out of it’s way to support using inheritance with page objects. This means that you can define an at checker in a common base class that reads our meta pageId property and have that used for each subclass.

import geb.*

abstract class GrailsPage extends Page {

    // To be overridden by subclasses
    static controller = null
    static action = null

    static at = {
        // delegate here is the original page _instance_ (i.e. the subclass)

        def expectedPageControllerName = delegate.class.controller
        if (expectedPageControllerName == null) {
            throw new IllegalStateException("${delegate.class} forgot to declare which controller it belongs to")
        }

        def expectedPageActionName = delegate.class.action
        if (expectedPageActionName == null) {
            throw new IllegalStateException("${delegate.class} forgot to declare which action it is")
        }

        def actualPageControllerName = controllerName
        def actualPageActionName = actionName

        assert actualPageControllerName == expectedPageControllerName
        assert actualPageActionName == expectedPageActionName

        true // at checkers must return true
    }

    static content = {
        pageId { $("meta", name: "pageId").@content }
        controllerName { pageId.split('\\.')[0] }
        actionName { pageId.split('\\.')[1] }
    }

}

Here we do three things:

  1. declare static ‘controller’ and ‘action’ properties that subclasses will populate (more on this later)
  2. declare an “at checker” that compares the declared controller/action against those in the page
  3. declare what the controllerName and actionName bits of content on the page are (consult the Book Of Geb for more on this content DSL)

We now have a rock solid page identification mechanism that from here on in in the development and testing of our application costs us almost nothing. The only thing you need to do when writing new page objects is set the controller and action static properties…

class ViewCartPage extends GrailsPage {
    static controller = "cart"
    static action = "view"
}

Or in the case where all your actions for a particular controller share content, you may want to have an abstract base class for all actions of that controller…

abstract class CartPage extends GrailsPage {
    static controller = "cart"
}

class ViewCartPage extends CartPage {
    static action = "view"
}

Geb and Inheritance (and Groovy)

This is made possible by Geb supporting inheritance of content definitions (content definitions are merged) and Groovy supporting a dynamic resolution of static methods and properties.

Given the above classes, the following works…

assert ViewCartPage.controller == "cart"

However, if we were calling this from Java, it would not work. In Java, static methods/properties are never inherited like they are for all intents and purposes in Groovy. This means that when requesting a page class’s “at checker” it will search the inheritance hierarchy for one (e.g. assert ViewCartPage.at == GrailsPage.at). This also means that at any point in the inheritance hierarchy you can override any static method/property defined in a super class (but it only works if calling from Groovy).

Summary

We discussed a useful pattern for page identification (“at checking” in Geb parlance) with Geb and Grails. I have used this pattern in anger and have found it to be very useful. Give it a try.

Posted: Aug 26th, 2010 @ 7:22 pm

Tags: #software  #grails  #geb  

Comments

Annotation Driven Extensions With Spock

The following is an introduction to writing extensions with everybody’s favourite testing tool Spock. Like all things in Spock, extensions are easy to use and require little ceremony. We are going to build an extension that times various parts of test execution and blindly writes the times to standard out.

Please note that the API we are going to go through should not be considered stable/final.

We are building against Spock 0.5-SNAPSHOT and the following APIs may change on the road to 1.0.

Annotation Driven

Our extension is going to be annotation driven. We are going to provide an annotation that users can place on various parts of their specs. At the core of this is the IAnnotationDrivenExtension contract…

package org.spockframework.runtime.extension;

import java.lang.annotation.Annotation;
import org.spockframework.runtime.model.*;

public interface IAnnotationDrivenExtension<T extends Annotation> {
  void visitSpecAnnotation(T annotation, SpecInfo spec);
  void visitFeatureAnnotation(T annotation, FeatureInfo feature);
  void visitFixtureAnnotation(T annotation, MethodInfo fixtureMethod);
  void visitFieldAnnotation(T annotation, FieldInfo field);
  void visitSpec(SpecInfo spec);
}

You’ll notice that (almost) all of Spock’s internals are implemented in Java. In this exercise we will implement our extension bits in Groovy.

Annotation driven extensions implement the Visitor Pattern, and Spock will invoke your visitation method for each annotation of your type present on the spec (We’ll discuss the visitSpec() method later).

These methods all take the annotation instance and an info object which describes the annotated thing. For more detail on each of these info types above what we will go through in this exercise, check them out in the Spock source. They are pretty straightforward.

The Annotation

We need to wire our annotation up to our extension. We declare our annotation like normal, but annotate it with the IAnnotationDrivenExtension implementation that backs it.

import java.lang.annotation.*
import org.spockframework.runtime.extension.ExtensionAnnotation

@Retention(RetentionPolicy.RUNTIME)
@Target([ElementType.TYPE, ElementType.METHOD])

@ExtensionAnnotation(TimingExtension)

public @interface Time {}

Here we have declared a new annotation called @Time that takes no parameters and can be placed on types (in our context, the spec class) and methods. The @ExtensionAnnotation meta annotation is how tell Spock who deals with the @Time annotation.

The Extension

Now we need to actual implement our extension. As you would expect, Spock provides a AbstractAnnotationDrivenExtension super class that we can use. This allows us to only implement the methods we need to. In our case, we don’t need the visitFieldAnnotation() method.

import org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension
import org.spockframework.runtime.model.SpecInfo
import org.spockframework.runtime.model.FeatureInfo
import org.spockframework.runtime.model.MethodInfo

class TimingExtension extends AbstractAnnotationDrivenExtension<Time> {
  def timeSpec = false
  def timedFeatures = []

  void visitSpecAnnotation(Time annotation, SpecInfo spec) {
    timeSpec = true
  }

  void visitFeatureAnnotation(Time annotation, FeatureInfo feature) {
    timedFeatures << feature.name
  }

  void visitSpec(SpecInfo spec) {
    spec.addListener(new TimingRunListener(timeSpec, timedFeatures)
  }
}

Here we simply collect information on which things we are timing, then add a run listener (explained below) that will do the timing.

The implementation of the visitation methods in AbstractAnnotationDrivenExtension always throw an org.spockframework.runtime.InvalidSpecException. Our annotation can legally be placed on any fixture methods according to it’s definition, but that doesn’t make sense in the context of our extension. Because we have not overridden the visitFixtureAnnotation() method in our extension, if the user annotates a fixture method with @Time, they will get a nice error message from Spock that tells them that that is invalid.

It’s important to consider that there is guaranteed to only ever be one instance of an extension for each spec. Spock will create an instance of your extension the first time it encounters your annotation, and then reuse that instance when it encounters later annotations (in the same spec).

Listening In

Spock has it’s own execution listening API specified by IRunListener.

package org.spockframework.runtime;

import org.spockframework.runtime.extension.builtin.StepwiseExtension;
import org.spockframework.runtime.model.*;

public interface IRunListener {
  void beforeSpec(SpecInfo spec);
  void beforeFeature(FeatureInfo feature);
  void beforeIteration(IterationInfo iteration);
  void afterIteration(IterationInfo iteration);
  void afterFeature(FeatureInfo feature);
  void afterSpec(SpecInfo spec);
  void error(ErrorInfo error);
  void specSkipped(SpecInfo spec);
  void featureSkipped(FeatureInfo feature);
}

This is all pretty straightforward, but you may be wondering about beforeIteration() and afterIteration(). This are for parameterised (or data-driven) feature methods and are called for each set of parameters.

Again, we have convenient super class to work with.

import org.spockframework.runtime.AbstractRunListener;
import org.spockframework.runtime.model.*;

class TimingRunListener extends AbstractRunListener {

  def timeSpec = false
  def specStartTime
  def featureStartTimes = [:]

  TimingRunListener(timeSpec, timedFeatures, timedFixtures) {
    this.timeSpec = timeSpec
    timedFeatures.each { featureTimes[it] = null }
  }

  private now() {
    System.currentTimeMillis()
  }

  private start(name) {
    println "starting $name …"
  }

  private done(name, started, finished = now()) {
    println "$name took ${finished - started} milliseconds"
  }

  void beforeSpec(SpecInfo spec) {
    if (timeSpec) {
      specStartTime = now()
      start("spec '$spec.name'")
    }
  }

  void beforeFeature(FeatureInfo feature) {
    if (featureStartTimes.containsKey(feature.name)) {
      featureStartTimes[feature.name] = now()
      start("feature '$feature.name'")
    }
  }

  void afterFeature(FeatureInfo feature) {
    def startedAt = featureStartTimes[feature.name]
    if (startedAt) {
      echo("feature '$feature.name'", startedAt)
    }
  }

  void afterSpec(SpecInfo spec) {
    if (specStartTime) {
      echo("spec '$spec.name'", specStartTime)
    }
  }
}

Our extension is now complete… let’s try it out.

In Action

Now all we have to do is annotate our spec…

import spock.lang.*

@Time
class DoingStuff extends Specification {

  @Time
  def "a b c"() {
    when:
    Thread.sleep(1000)
    then:
    true
  }

}

If we were to run this spec we would see something like…

starting spec 'DoingStuff' …
starting feature 'a b c' …
feature 'a b c' took 1000 milliseconds
spec 'DoingStuff' took 1500 milliseconds

Obviously the times are made up but you get the point.

The Real World

Spock ships with a bunch of extensions (as of today in 0.5-SNAPSHOT):

For more info on any of these extensions, check out their javadoc comments.

You could very easily make your own extensions specific to your projects to make your life easier. You could load data fixtures, establish connections… all kinds of things.

Summary

So that’s “Annotation Driven Extensions” with the Spock Framework.

Go forth and create some… and may the force be with you (wait… what?)

Posted: Aug 18th, 2010 @ 10:58 pm

Tags: #groovy spock  

Comments

Proposal: Grails Plugin Collective

The following is a proposal for, and a request for comment on, the idea of a semi-structured combination of social and technological systems and norms to initiate, develop and maintain Grails plugins.

The Problem Being Addressed

Typically, a plugin is born through inspiration or necessity. It’s not uncommon that the original author at some point stops maintaining or developing a frequently-used or promising plugin. There are many reasons for this and they are in no way unique to the Grails ecosystem. People contribute and move on as is their want and well intentioned developers can quickly lose interest in developing a plugin due to roadblocks and lack of knowledge, experience and feedback.As a Software Developer using Grails professionally, the availability of a high quality plugin makes a significant product difference; and conversely an unsuccessful attempt to use a plugin due to bugs or lack of documentation costs real time. Often when finding an issue and fixing it, getting that fix back into the community takes considerable effort in coordinating with the plugin developer/maintainer who may or may not be around.

As a plugin developer, during busy times it can be hard to keep up with bug reports, feature requests and Grails upgrades. It’s also concerning that knowledge and understanding of the plugins I have authored rest largely with myself, creating a single point of failure. It would be much better if there were other people who could (and did) maintain and improve things in my (or any other author’s) absence.

The Proposed Solution

To remedy this situation, I propose that a self-organised, distributed, democratic, collective be formed… to foster, develop and maintain Grails plugins. I am calling this idea the “Grails Plugin Collective” for the time being.

The social structure is what would be the most interesting and, ultimately, enabling. It would allow members to work across plugins, scratching their own itches, and getting those fixes/features into release with minimal effort without risking quality. It would also enable steering and guiding the direction of plugins while allowing members to freely propose ideas and alternatives. Due to Grails’ “convention over configuration” nature, this becomes critically important. Hopefully, the collective wisdom of a group of individuals results in a highly consistent, conventional approach to how plugins work.

Goals and Aims

Relationship with VMWare and certification

I propose that the collective should be an entity outside of VMWare. This does not exclude VMWare employees from participating in the collective by any means, or from having some kind of special role. It purely means that the entity is not bound to VMWare in any way other than through the licensing arrangement of any software owned by VMWare.

I also propose that if a plugin certification scheme is ever established, it be done completely separately to the collective. I imagine that many of the collectivised plugins would aim for certification if at all possible, but in this respect they would be no different to other community plugins.

Procedures and Principles

The collective should aim to operate with the least amount of bureaucracy and procedure that is required. The core idea is that as a democratic structure, all proposals are put to a vote. Members will have a relatively short time frame (proposed: 48 hours) to vote. A certain proportion of the votes cast must be affirmative for the proposal to succeed. It’s likely that there would also be some sort of veto mechanism for things that are extremely time critical.

I image the following kinds of things would be voted on:

Initial Membership

Being that what is being proposed is a self-organising, democratic social structure, I am hesitant to be to prescriptive about how such a thing might work in terms of my vision. I am interested in getting other people’s ideas.

An initial membership also needs to be put together. This will be somewhat of a challenge for a democratic outfit. To get the ball rolling, I suggest that the VMWare Grails team propose an initial membership of roughly 10 people (likely including themselves). From there, the collective can self organise and induct new members over time.

So what are your thoughts? Is such an initiative worthwhile? Could it work? Could it succeed in raising and maintaining the quality of selected Grails plugins? Are there other such initiatives that we could learn from? What kind of social practices could be put in place to support rapid development while maintaining consistency and quality?

Feel free to leave your opinion either here or on the grails-user mailing list.

Posted: Jun 7th, 2010 @ 9:29 pm

Tags: #software  #grails  

Comments

Putting the Artefact API to work in your Grails app

I haven’t seen many cases of people putting the Grails’ artefact API to use in their application. It’s likely that most Grails’ users aren’t aware that it exists, which in many ways is a good thing… it is after all an implementation concern.

You can however put it to work in your own application.

What is it?

Perhaps it’s best to discuss what an artefact is in Grails first. An example of an artefact is a service class. Think of what happens when your grails application starts; it finds all the service classes, creates an instance of each (typically) and autowires the dependencies. Grails defines a class whose instances represent a single service class and an associated handler. This is what I am collectively calling the Artefact API.

Why use it?

The biggest reason these days is by far the hot reloading support. That is, if you change an artefact class while the application is running, Grails (with some help from you) will reload the class and you get the changes without a restart. Of course, we are all familiar with this.

There is a more subtle benefit though. You may have some kind of prominent & pervasive concept in your application (like a service is a concept). You might find that creating an artefact for this concept can make your life easier.

An example use case

Consider some kind of eStore, with a wide range of products. Our products have simple persistence requirements but can have wildly varying behaviours in the system, which are likely to get more complex over time. I try to avoid extensive subclassing of domain objects when the classes primarily vary in behaviour and not data. So we need to find another way to implement the varying behaviour.

The ProductHandler

Each product is going to provide a handler (terrible name I know) that is responsible for the majority of the product’s behaviour. Here is our product domain class…

class Product {
    String name
    
    // don't want to try and persist the handler
    static transients = ['handler'] 
    
    ProductHandler getHandler() {
        // somehow get the handler for this product
    }
}

And we have a ProductHandler interface for good measure…

interface ProductHandler {
    void setProduct(Product)
    boolean isCanBeSold()
}}

A non artefact solution

One kind of traditional approach would be to have each product persist a key that refers to a particular product handler, and to have each product handler class register itself with some kind of registry.

class Product {
    String name
    String handlerKey
    
    def productHandlerService // autowired 
    
    // don't want to try and persist the handler
    static transients = ['handler']
    
    protected handler
    ProductHandler getHandler() {
        if (!handler) {
            handler = productHandlerService[this]
        }
        handler
    }
}

// Our registry
import grails.spring.BeanBuilder
class ProductHandlerService {
    def grailsApplication // autowired
    static private registry = [:].asSynchronized()
    
    static register(String key, Class handlerClass) {
        registry[key] = handlerClass // should check that handlerClass implements ProductHandler
    }
    
    protected createBeanBuilder() {
        new BeanBuilder(grailsApplication.mainContext, grailsApplication.classLoader)
    }
    
    protected instantiateHandler(handlerClass, Product product) {
        createBeanBuilder().with {
            beans {
                handler(handlerClass, product: product) {
                    // autowire the handler so it can use services etc.
                    it.autowire = true
                }
            }
            createApplicationContext().getBean('handler')
        }
    }
    
    def getAt(Product product) {
        def handlerClass = registry[product.handlerKey] // assume there is always a handler
        instantiateHandler(handlerClass, product)
    }
}

// Example Handler (in src/groovy dir)
class OnlyOnTuesdayProductHandler implements ProductHandler {
    static {
        ProductHandlerService.register('onlyOnTuesday', OnlyOnTuesdayProductHandler)
    }
    Product product
    boolean isCanBeSold() {
        new GregorianCalendar().get(Calendar.DAY_OF_WEEK) == Calendar.TUESDAY
    }
}

This will get the job done (albeit in a cumbersome way), but it suffers from ProductHandler implementations not being hot-reloadable.

Creating a ProductHandler artefact

We can make things a bit easier and support hot reloading by creating an artefact for product handlers.

To do this we need a plugin…

class ProductHandlerGrailsPlugin {
    def version = "0.1"
    def grailsVersion = "1.2.* > *"
    
    // register the artefact handler
    def artefacts = [ProductHandlerArtefactHandler]
    
    // watch for any changes in these directories
    def watchedResources = [
        "file:./grails-app/productHandlers/**/*ProductHandler.groovy",
        "file:../../plugins/*/productHandlers/**/*ProductHandler.groovy"
    ]
    
    // Grails calls this when one of the files matching 'watchedResources' changes.
    // We have to actually swap in the new class when the source changes
    // There isn't anything special here, it's just boilerplate.
    def onChange = { event ->
        if (application.isArtefactOfType(ProductHandlerArtefactHandler.TYPE, event.source)) {
            def oldClass = application.getProductHandlerClass(event.source.name)
            application.addArtefact(ProductHandlerArtefactHandler.TYPE, event.source)

            // Reload subclasses
            application.productHandlerClasses.each {
                if (it.clazz != event.source && oldClass.clazz.isAssignableFrom(it.clazz)) {
                    def newClass = application.classLoader.reloadClass(it.clazz.name)
                    application.addArtefact(ProductHandlerArtefactHandler.TYPE, newClass)
                }
            }
        }
    }
}

We also need a artefact handler implementation (which has to be in Java due to legacy reasons)…

import org.codehaus.groovy.grails.commons.ArtefactHandlerAdapter;

public class ProductHandlerArtefactHandler extends ArtefactHandlerAdapter {

    // the name for these artefacts in the application
    static public final String TYPE = "ProductHandler"; 

    // the suffix of all product handler classes (i.e. how they are identified as product handlers)
    static public final String SUFFIX = "ProductHandler"; 
    
    public ProductHandlerArtefactHandler() {
        super(TYPE, ProductHandlerClass.class, DefaultProductHandlerClass.class, SUFFIX);
    }
}

And a ProductHandlerClass interface (again in Java)…

import org.codehaus.groovy.grails.commons.GrailsClass;

public interface ProductHandlerClass extends GrailsClass {}

And a DefaultProductHandlerClass implementation of that interface (again in Java)…

import org.codehaus.groovy.grails.commons.AbstractGrailsClass;
import org.codehaus.groovy.grails.commons.GrailsClassUtils;
 
public class DefaultProductHandlerClass extends AbstractGrailsClass implements ProductHandlerClass {

    public DefaultProductHandlerClass(Class clazz) {
        super(clazz, ProductHandlerArtefactHandler.SUFFIX);
    }
    
    // This method will get the static property 'key' on the underlying 
    // ProductHandler class that it represents.
    public String getKey() { 
        Object key = GrailsClassUtils.getStaticPropertyValue(getClazz(), "key");
        if (key == null) {
            return null;
        } else {
            return key.toString();
        }
    }
}

That’s a shotgun intro to the Grails Artefact API classes like GrailsClass and ArtefactHandlerAdapter just covering the stuff we need. Check out the linked to source for deeper detail.

Here is what we have done…

  1. Create a plugin that registers an artefact handler for product handlers
  2. Register for changes to source in grails-app/productHandlers in the app and plugins
  3. Provide an onChange handler that reloads product handler classes when they change
  4. Provide an ArtefactHandler implementation that specifies what a product handler class is
  5. Provide a GrailsClass subinterface for product handler classes
  6. Provide an implementation of that interface that returns the static property key on the underlying class (among other things)

Putting it together

Armed with our new artefact, we can now simplify our initial implementation…

// Our registry
import grails.spring.BeanBuilder
class ProductHandlerService {
    def grailsApplication // autowired
    
    protected createBeanBuilder() {
        new BeanBuilder(grailsApplication.mainContext, grailsApplication.classLoader)
    }
    
    protected instantiateHandler(handlerClass, Product product) {
        createBeanBuilder().with {
            beans {
                handler(handlerClass, product: product) {
                    // autowire the handler so it can use services etc.
                    it.autowire = true
                }
            }
            createApplicationContext().getBean('handler')
        }
    }
    
    def getAt(Product product) {
        def productHandlerClasses = grailsApplication.productHandlerClasses // a list of DefaultProductHandlerClass
        def handlerClass = productHandlerClasses.find { it.key == product.handlerKey } // find the one with the matching key
        instantiateHandler(handlerClass, product)
    }
}

// Example Handler (in grails-app/productHandlers dir)
class OnlyOnTuesdayProductHandler implements ProductHandler {
    static key = 'onlyOnTuesday'
    Product product
    boolean isCanBeSold() {
        new GregorianCalendar().get(Calendar.DAY_OF_WEEK) == Calendar.TUESDAY
    }
}

Being more conventional

Each of our product handler classes must specify a key, that products use to link themselves to a particular handler implementation. You could do away with this, and infer the key from the class name quite easily.

class ProductHandlerService {
    // …snip…
    
    def getAt(Product product) {
        def handlerClass = grailsApplication.getProductHandlerClass(product.handlerKey)
        instantiateHandler(handlerClass, product)
    }
}

The grailsApplication.getProductHandlerClass() method given the value "onlyOnTuesday" would return the OnlyOnTuesdayProductHandler class object.

In this particular case I personally wouldn’t do this as every time I renamed a product handler class I would have to update the products that use that handler in the DB, but other situations may not have this issue.

Summary

All product handler classes are now reloadable, which would obviously be a substantial productivity boost, without all that much work on our part. This approach could be used for any kind of concept or set of classes in your application that don’t fit into the standard controller, service, taglib etc. pattern.

The Artefact API can seem a bit confusing if you don’t take into consideration that this was the heart of Grails in the early days. It’s still there and is used by a great many plugins (e.g. grails-quartz) as well as being used extensively internally in Grails, but it doesn’t quite have the same role that it used to.

Hopefully this has shown you how you can, and why you might want to, use the artefact API internally in your applications.

Posted: Jun 1st, 2010 @ 10:42 pm

Tags: #software  #grails  

Comments

Forwarding/Chaining and models in Grails

I recently hit the case where I need to forward a request in Grails to a second action, but that action needed access to the model generated by the first (note that this is different to params). The Grails documentation doesn’t mention the ability to pass models when forwarding at all, but if you check the source code you can see that the capability is there.

What’s also missing is how to access the existing model in a forwarded to or chained to action. If you trace the code, you see that the model eventually gets passed to Spring’s [WebUtils.exposeRequestAttributes()](http://static.springsource.org/spring/docs/current/javadoc-api/org/springframework/web/util/WebUtils.html#exposeRequestAttributes(javax.servlet.ServletRequest, java.util.Map)) method, that simply makes each item in the model a request attribute. So in Grails you can access them via the request variable…

class MyController {
    
    def first = {
        forward(action: 'second', model: [thing: "thing"])
    }
    
    def second = {
        assert request.thing == "thing"
        // go forth and do stuff
    }
    
}

Why use model instead of params?

Params can only be strings where as you can pass any type via the model.

Posted: May 24th, 2010 @ 2:35 pm

Tags: #software  #grails  

Comments

Archive · RSS · Theme by Autumn