Grails - Controllers - Data Binding

Data Binding

Grails uses Spring's data binding facilities under the covers, but introduces a simplified syntax.

Binding Request Data to the Model

Request parameters get passed into web applications as strings, causing a typical scenario of having to convert each string value into its equivalent object representation. With Grails domain classes this is made simple by the "properties" property:

def save = {
  def b = new Book()
  b.properties = params
  b.save()
}
You can also use a domain classes constructor to achieve the same effect:

def save = {
  def b = new Book(params)
  b.save()
}

In the above example with one line of code the request parameters are auto-magically converted and set on the instance of Book. If you're using a command object or some other object that you want to bind data to you can use the "bindData" method present in controllers:

def sc = new SaveCommand()
bindData(sc, params)

Data binding with multiple domain classes

Since Grails 1.0 it is possible to bind data to multiple domain objects from the params object. Grails' params object is like a multi-dimensional hash and you can index into to isolate only a subset of the parameters to bind.

For example so you have an incoming request to /book/save?book.title=The%20Stand&author.name=Stephen%20King

The above request has parameters that are separated by a dot . character. If you wanted to bind properties to a Book domain class you could do:

def b = new Book(params['book'])
Notice how we use the prefix before the first dot of the "book.title" parameter to isolate only parameters below this level to bind. We could do the same with an Author domain class:
def a = new Author(params['author'])

Data binding and type conversion errors

Since Grails 1.0, Grails will also retain type conversion errors inside the {{errors}} property of a Grails domain class. Take this example:

class Book {
    …
    URL publisherURL
}

def params = [publisherURL:"a_bad_url"] def b = new Book(params)

In this case it is not possible to bind the string "a_bad_url" to the publisherURL property as a type mismatch error occurs. You can check for these like this:

def params = [publisherURL:"a_bad_url"]
def b = new Book(params)

if(b.hasErrors()) { println "The value ${b.errors.getFieldError('publisherURL').rejectedValue} is not a valid URL!" }

Typically what you want to do is render the errors on the original page that contained the form:

<g:renderErrors bean="${book}" />

With <g:renderErrors> it will look for a message to use for the error inside the grails-app/i18n/messages.properties file. You can use a generic error message handler such as:

typeMismatch.java.net.URL=The field {0} is not a valid URL
Or a more specific one:
typeMismatch.Book.publisherURL=The publisher URL you specified is not a valid URL