Grails Framework

This lecture about Grails assumes that you have already done the first three individual programming assignments, so you should know that Grails is a web framework built on the Groovy programming language. You know that Grails uses the MVC design pattern and if you follow the conventions, much of code is scaffolded for you. Although a goal of Grails is to prefers convention over configuration, there a number of configurations that need to be made. Your programming assignments actually edited almost all the configuration files. You also realize that plugins can extend the basic Grails framework, and you have installed several plugins.

This lecture will not start from the beginning, rather it will introduce more advance features than what your programming assignments introduced. However, this lecture of Grails is not an exhaustive list of all the advance topics in Grails. The Grails documentation is the best source for all the features of Grails.

http://grails.org/doc/latest/

Much of the material for this lecture comes from “The Definitive Guide to Grails 2” by Jeff Scott Brown and Graeme Rocher, a very good book, but it is a little out of date now because Grails 2.4 uses the assest-pipeline plugin rather than the resource plugin. Now, Grails is on version 3 which uses the gradle build. This lecture will proceed by going through some of the domain, controller and view advance features that I expect you will need for your projects.

Domain

Grails uses GORM for Object Relational Mapping to define the domain objects. Documentation for GORM is at

http://gorm.grails.org/latest/hibernate/manual/

Associations

Domain classes can have associations with each other much like tables in a database can be related to each other. In a database, tables can be related to each other by having a foreign key that points to a primary key in another table. Another way that tables can be associated to each other is by a third table called a join or junction table that pairs keys from each table.

An example of a domain class relation is the Author – Book domain classes in your programming class. An Author could have written many books. So an Author entry can be associated with many Book entries.

The simplest relationships are
• Many-to-one
• One-to-one
• One-to-many
• Many-to-many

Your programming assignment is an example of one-to-many. The Author domain has a one-to-many Book domains associated with it.

Many-to-one

The simplest relation to implement in Grails is many-to-one. You just reference the “one” domain in the “many” domain.

class Face {
    Nose nose
}
class Nose {
}

So a Face can have one Nose, but a Nose can be referenced by many Faces. Grails implements this relation with a Nose “foreign key” in the Face table.

One-to-One

Nose and Face should really be a one-to-one association. To make a one-to-one relations the Nose domain must reference the Face domain.

class Face {
    Nose nose
}
class Nose {
    static belongsTo = [face: Face]
}

The static property “belongsTo” puts a Nose foreign key in the Face table, just as above.

The term cascading refers to the behavior of saves, update and delete on the domain classes when you perform an operation on associated domains. In this case, the one-to-one association, when you save and delete Face, GROM will save and delete Nose. In other words, saves and delete will cascade from form Face to Nose. But when you delete a Nose, the Face is not deleted.

To make a Face, you need to make the Nose first.

new Face(nose:new Nose()).save()

A way to make the one-to-one bidirectional is to use the “hasOne” property, and then the cascading can go both directions.

class Face {
   static hasOne = [nose:Nose]
}
class Nose {
   Face face
}

This will put the Face foreign key in the Nose table. The cascades will go both directions.

One-to-many

To indicate a one to many association, add a static property “hasMany” to the “one” domain.

class Author {
   static hasMany = [books: Book]
    String name
}

class Book {
    String title
}

Grails will implement this association with a join table. The join table is a third table probably called AuthorBook and will associate Author keys with Book keys.

When you retrieve from the “one” table Grails will automatically inject a Set of the “many.”

def a = Author.get(1)
for (book in a.books) {
    println book.title
}

In this case saving and updating on Author will cascade to the Book domain, but deleting an Author will not delete the books. Adding the “belongsTo” property to the “many” domain will cascade the deletes from Author to Book.

class Author {
    static hasMany = [books: Book]
     String name
}

class Book {
    static belongsTo = [author: Author]
    String title
}

Note sometimes associations can become complicated when the “many” domain class references more than one “one” domain. For example Airports can have many flights, and a flight is associated with two airports, the departure and destination airports. See the GORM documentation for how to handle this.

http://gorm.grails.org/latest/hibernate/manual/#gormAssociation

Many-to-Many

The “many-to-many” association is specified by using “hasMany” in both domain classes. One domain has to be owner by adding the “belongsTo” property to the other domain. Cascading is from the owner domain.

 class Book {
     static belongsTo = Author
     static hasMany = [authors:Author]
     String title
 }

 class Author {
      static hasMany = [books:Book]
      String name
 }

So in this case you have to make the Books first.

 new Author(name:"Stephen King")
    .addToBooks(new Book(title:"The Stand"))
    .addToBooks(new Book(title:"The Shining"))
    .save()

Documentation for GORM associations is at

http://gorm.grails.org/latest/hibernate/manual/#gormAssociation

Queries

Queries are how you retrieve data from a database. You have already seen how the “list” method in the domain class can retrieve all the table entries. That is a query. The response from the list method can be modified with map argument.

You can retrieve a single table entry if you know the id by using the “get” method.

 def book = Book.get(23)

Dynamic Finders

GORM has “dynamic finders.”

http://gorm.grails.org/latest/hibernate/manual/#finders

Dynamic finders are methods that are created dynamically at run time. They are best explained by example.

 def book = Book.findByTitle("The Stand")
 book = Book.findByTitleLike("Harry Pot")
 book = Book.findByReleaseDateBetween(firstDate, secondDate)
 book = Book.findByReleaseDateGreaterThan(someDate)
 book = Book.findByTitleLikeOrReleaseDateLessThan("Something", someDate)

See the findBy and findByAll documentation in the Domain class quick reference.

http://grails.org/doc/latest/ref/Domain%20Classes/findBy.html
http://grails.org/doc/latest/ref/Domain%20Classes/findAllBy.html

The general form of the method name is

Book.findBy([Property][Comparator][Boolean Operator])?[Property][Comparator]

The part of the expressions marked by “(…)? is optional. The property is a domain field, in other words a table header. The simplest expression is

 def book = Book.findByTitle("The Stand")

In this example the equality operator is assumed.

Comparators include:

• InList – In the list of given values
• LessThan – less than a given value
• LessThanEquals – less than or equal a given value
• GreaterThan – greater than a given value
• GreaterThanEquals – greater than or equal a given value
• Like – Equivalent to a SQL like expression
• Ilike – Similar to a Like, except case insensitive
• NotEqual – Negates equality
• InRange – Between the from and to values of a Groovy Range
• Rlike – Performs a Regexp LIKE in MySQL or Oracle otherwise falls back to Like
• Between – Between two values (requires two arguments)
• IsNotNull – Not a null value (doesn’t take an argument)
• IsNull – Is a null value (doesn’t take an argument)

Where Querying

The dynamic finders are restricted to queries into a single table. Sometimes you want the query result to dependent on associated tables then you must use the “where” query.

http://gorm.grails.org/latest/hibernate/manual/#whereQueries

You can also use a where query to retrieve results dependent on the same table.

 def query = Person.where {
     firstName == "Bart"
 }
 Person bart = query.find()

You first define a query with the test as a closure IN the “where” method for the Domain. Then, you retrieve the results by calling the “find” method on the query. You can use all the Groovy Boolean tests on any property in the domain. You CANNOT define the testing closure outside the where method. In other words this will NOT work.

 //This will not work!
 def callable = {
    lastName == "Simpson"
 }
 def query = Person.where(callable)

To generate results dependent on other tables, the table making the “where” clause must have a reference to the other table. For example.

 def query = Pet.where {
    owner.firstName == "Joe" || owner.firstName == "Fred"
 }

In this case owner is a property of Pet and references the Owner table.

The above material is a very brief introduction of the material in the GORM and Grails documentation.

http://grails.org/doc/latest/guide/GORM.html

http://gorm.grails.org/latest/hibernate/manual/

Constraints and Validation

Grails uses the “constrain” closure for validation. This is appropriate because the domain class is the representation of the data, so it should be expressed there.

 class User {
    String login
    String password
    String email
    Integer age
    static constraints = {
        …
    }
 }

In the domain class “constraints” is a closure. You then use methods calls in the constraint closure to specify the constraint for each property of the domain.

class User {
   ...
   static constraints = {
       login size: 5..15, blank: false, unique: true
       password size: 5..15, blank: false
       email email: true, blank: false
       age min: 18
    }
 }

Note that “login size: 5..15, blank: false, unique: true” could have been written

login([ size: 5..15, blank: false, unique: true ])

So “login” is a method and “size”, “blank” and “unique” are keys in a map argument. The methods are named after the properties in the domain class and are built for you by Grails, and the key are different constraints.

Note that “5..15” is using the groovy range operator, “…”, so the size of “login can be 5 to 15 characters long.

The “blank” key specifies if the property value can be empty. For login the string cannot be empty.
The “unique” key specifies that the login string must be unique in the database table. Note that the order of properties in the constraints closure will set the order of properties in the table and the return from the list method.

The possible key-constraints are found in the Quick Reference under the Constraints.

• blank
• creditCard
• email
• inList
• matches
• max
• maxSize
• min
• minSize
• notEqual
• nullable
• range
• scale
• size
• unique
• url
• validator

In general, their use is obvious. Read the documentation on how to use them. For example “inList” constrains the property value to a list that you provide. It will be implemented as a dropdown in the scaffolded view.

Types, Nulls and Required Constraints

By default, domain properties are required to pass the validation (See below about validation). If you want the property not be required then in the domain’s closure the property’s “nullable” attribute must be set to true. For example

Class Item {
   Integer number
   String name
   int anotherNumber

   static constraints = {
        number (nullable: true)
        name (nullable: true, blank: true)
    }
}

Strings need to be both nullable and blank true. Primitive types, such as anotherNumber above, cannot be nullable true. The scaffolding views will be made and there will be no error if you make a primitive type nullable, but the view will show a default value of zero and the database generated by Hibernate will show that the column is “NOT NULL.”

Validator

The validator constraint can be used to make custom constraints. For example suppose that the possible answers to a survey is listed in “Survey.answers.” Then to validate the Response.answer

class Response {
    Survey survey
    Answer answer

    static constraints = {
       survey blank: false
       answer blank: false, validator: { val, obj -> val in obj.survey.answers }
    }
}

Note that “val” is the value of the form field and “obj” is the domain instance being validated, essentially “this.” There is also a third argument, “errors,” that you can use to attach a message to the Error object associated with the domain.

In the simplest form the validator closure returns a Boolean for the result of the validation.

 even validator: { val ->
     return (val % 2) == 0
 }

More typically, validators return true if the entry passes validation and a list if there is an error in validation.

Messages (a short diversion)

To understand the next validator example, we need to first understand messages.

Messages are the string/text of your website. Best practice is not to hard code string/text in the views. Rather you associate the string/text with a message. Messages are found in the grails-app/i18n/messages.properties file. Which is list of properties and values separated by “=”, for example:

default.paginate.prev=Previous
default.paginate.next=Next
default.boolean.true=True
default.boolean.false=False

In the above example “default.paginate.prev” is a String variable that you can use in your code. The value of the string is “Previous.”

The message value can have “variable” sub-strings that are passed to it in an order list. The sub-strings are called parameters. The parameters in the list are indexed by {0}, {1}, {2} etc, For example the {0} below.

default.create.label=Create {0}

Messages are typically used in the view with the “g:message” tag and the sub-string list of parameters are passed by the “args” attribute of the tag.

<g:message code="default.create.label" args="[entityName]" />

Back to Validator returning a List

The constraint can also return a list. This is generally done when the entry is not valid and is used to help generate the error message. The validator will find the message by first mapping to the class name and property name that is being validated. The first string in the list returned by the validator will make the message more specific by adding the string to  the class name and property name, in other words class name, property nam and then the first string in the list. This will be used to search in the message.property file. For example

className.propertyName.theFristSringInList

The example below test for the existence of an entry. If it does not exist then it creates an error message.

class Person{
    String name

    static constraints = {
        name validator: {
            if (!it) return ['entryMissing']
        }
// This maps to the message:
// person.name.entryMissing = Please enter a name in the field {0}
}

The parameter list given to the error message from a validator has some parameters automatically added to the list. Parameters 0 to 2 are automatically mapped to 0: property name, 1: class name, 2: property value.

So in the example above, the list returned from the validator, indicates the message, “person.name entryMissing”. The 0 parameter for the message is the property, “name.”

The list returned by the validator can have addition strings. These are mapped from index 3 on in the parameter list for the message.

Controllers

In your programming assignments, you have learned to create a controller, send the model to the view and how to associate a view with the controller. In this section, you’ll learn some more tool to use with controllers. Many of the tools are properties that are injected into your controller when the controller is instantiated.

Logging

Logging prints messages to a log file or to the console. These messages are used to record errors, warnings, gather debugging info, etc. In your programming assignment, you probably used “println” to write debugging information, but that is not always the best technique, for example in the production environment, it is better to write to a file.

A logger writes messages at different levels. The priority of the levels are

1. off
2. fatal
3. error
4. warn
5. info
6. debug
7. trace
8. all

Note that “1. off” and “8.all” are not really levels. They exist only to specify the top and bottom of the priority list and to configure a logger.

Loggers are injected to all your grails app artifacts. The injected logger is accessed using the “log” object. To use the logger you call the method corresponding to level of priority of the message. For example

log.debug("My debugging message.")

will write a debug message.

If you do this in a controller, for example

class HomeController {

    def index {
       log.debug("In index method)
       …
    }
}

The debug log message will probably not appear in the console. You need to configure the logger. Loggers are configured by the “log4j.main” closure in the Config.groovy file. To configure the logger you specify the level followed by a list of all the loggers who should print at that level or higher. For example, several loggers are already specified in the log4j closure.

log4j.main = {
   error 'org.codehaus.groovy.grails.web.servlet', // controllers
         'org.codehaus.groovy.grails.web.pages', // GSP
         'org.codehaus.groovy.grails.web.sitemesh', // layouts
         'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
         'org.codehaus.groovy.grails.web.mapping', // URL mapping
         'org.codehaus.groovy.grails.commons', // core / classloading
         'org.codehaus.groovy.grails.plugins', // plugins
         'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
         'org.springframework',
         'org.hibernate',
         'net.sf.ehcache.hibernate'
 }

In the above the “org.codehaus.groovy.grails.web.servlet” logger will print error and fatal messages.

The name of the logger that are injected into your classes are specified

grails.app.<type>.<className>

Where the <type> is “controllers”, “domains”, “views”, or “services” and <className> is the full class name including the package. So to configure the injected logger in your HomeController you would add to the log4j closure.

log4j.main = {
    debug 'grails.app.controllers.cs4760progassign.HomeController'
 }

Although this will work for logging in the HomeController, it will not enable logging for any other artifact. If you are logging from one artifact you probably want to log in all artifacts. You can specify a group of loggers. For example

log4j.main = {
     debug 'grails.app'
 }

This will enable the injected loggers to write debug messages and higher.

This is good enough if you only want to log to the console. More configurations are required to write to a file. You need to make an Appender and associate it with a level and a logger. There are four Appenders available.

  • jdbc – Logs to a JDBC connection.
  • console – Logs to the console.
  • file – Logs to a single file.
  • rollingFile – Logs to files, for example a new file each day.

The Appenders are created and configured in the Appenders closure in the log4j closure. For example to create a file Appender, you would add this Appender closure.

log4j.main = {
    appender {
       file name: 'myFileAppender', file: 'target/myLog.log'
    }
 }

This will create an Appender called ‘myFileAppender’ that writes to the file “target/myLog.log” which is adjacent to “stacktrace.log” in the “target directory.” Although this will create the file, it is still not sufficient for log messages to appear in the file. The Appender needs to be associated with the logger. You do this when you specify the level of logging in the log4j closure.

log4j.main = {
    appender {
       file name: 'myFileAppender', file: 'target/myLog.log'
     }
     debug myFileAppender: 'grails.app'
 }

Now it will work and log to the file and the console. There is much more to logging. Read about them in the documentation.

http://grails.org/doc/latest/guide/conf.html#logging

Scope Objects

You are familiar with namespace variable scoping in applications, meaning the namespace that a variable is defined in and can be used in. In a web application scoping is more complicated than the namespace. Variables also have time scope. Most objects only exist during a single request. Some objects can exist longer, these objects are

  • params – a map of the request parameters in either the URL in a GET request or from a form submit in a POST request.
  • request – a HttpServletRequest object, and exist for only a single request to the server
  • flash – a object that exist with the current request and the next request
  • session – a HttpSession object, and exist with a user’s visit to the domain
  • servletContext –a ServletContext object, exist for the lifetime of the application

The scope objects params and request  are created for every request to the server. A single session parameter is created when the user visit the domain and continues to navigate domain. Typically it expires when the user logouts or after some time limit. The servletContext exist for the lifetime of the web app, but you’ll seldom have need for this object.

All of these scope objects are available to all your artifacts, including controllers and views. You can set and get objects in these scope objects by using the dot format. For example

def user = session.username
session.myObject = myObject

When a user fills out a form and hits the submit button, a request is made to the server. The form data consists of name-value pairs that are put into the params object. The controller can access them. For example when creating an Author named “Bob Jones” using the create form

In the Author/create view

<form action="/cs4760progassign/author/save" method="post" >
    <fieldset class="form">
        …
       <div class="fieldcontain required">
           <label for="name">
               Name <span class="required-indicator">*</span>
           </label>
       <input type="text" name="name" required="" value="" id="name" />
       </div>
    </fieldset>
    <fieldset class="buttons">
       <input type="submit" name="create" class="save" value="Create" id="create" />
    </fieldset>
 </form>

After clicking the submit button. A POST request to “/cs4760progassign/author/save” will be made and the params will contain

name="Bob Jones"
create="Create" // a hidden form entry, see the submit button.

Grails also puts into the params entries

controller="author"
action="save"

Data Binding

Data binding is the process of taking form data, populating the domain object and updating the database. For example in a the Author controller we could have

class AuthorController {
    def save(){
       def author = new Author()
       author.name = params.name
       author.save()
    }
 }

As our Author domain class becomes more complicated with many more properties, the template code above will get more complicated and difficult to maintain. If the fields in the form data match those of the property names in the domain class then the binding can be automatic.

class AuthorController {
   def save(){
       def author = new Author(params)
       author.save()
    }
 }

Of course, you cannot use the above technique when you are updating a table entry. In that case, you would get the domain instance from the table and set the properties map of the domain.

class AuthorController {
     def update(){
         def author = Author.get(params.id)
         author.properites = params
         author.save()
     }
 }

Note that Grails will only fill in matching property names.

Validating Data

Validation has two phases. The first phase occurs when the request parameters are matched with the domain properties, such as in this line.

author.properites = params

In this phase, Grails must make type conversions from the params to the Author properties. If the types cannot be converted then Grails will set the database entry to read only and author cannot be updated.

The second phase occurs when the domain instance is saved, such as

author.save()

or explicitly validated

author.validate()

At this points, Grails will check the constraints for each property specified in the constraint closure. If there are errors, they are added to the “errors” property of the domain instance. You can test for errors using the hasErrors() method or cycle through the error.

author.errors.allErrors.each { println it.code }

You can also render the errors in the view.

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

Data Binding to Multiple Domain Objects

In the previous example data binding of the author name, the name of the input field for the author’s name was just called “name” and that matched the domain class property, name. If we want to bind multiple domain objects then the names of the input fields need to be more explicit. For example consider a form that creates simultaneously a book and an author.

The view

... 
<input type="text" name="author.name" />
<input type="text" name="book.title" />
<input type="number" name="book.publishYear" />
...

Then in the controller

 def author = new Author( params["author"] )
     .addToBooks( book = new Book( params["book"] ) )
     .save()

There is much more to data binding. Read the data binding section in the Web Layer chapter.

http://grails.org/doc/latest/guide/theWebLayer.html#dataBinding

Views

Scriptlet Blocks

Any groovy code can be inserted into the GSP page using the scriptlet block <% … %>

<html>
 <body>
    <% 3.times { %>
       <p>I'm printed three times. </p>
    <% } %>
 </body>
 </html>

Scriptlets do not output to the page. You can use standard output to output to the page.

<% out << "Hello World!" %>

or the short hand

<%= "Hello World! %>

In practice, you normally do not use the above scriptlet tag. To output to the page use the G-string with curly brackets.

<p>${author.name}</p>

G-Tag

Also, you should not need to use the scriptlets tag for controlling output. A better alternative are the built in g-tags.

Setting Variables

You can set variables using the g:set tag.

<g: set var="bookTitle" value="${book.title}">

Then the variable “bookTitle” will have the value of book.title.

Logical Tags

G-tags include if-else tags.

<g:if test="${book?.publishYear > 2014}">
    Year is too new.
</g:if>
</g:elseif test="${book?.publishYear < 1900}
    Year is too old.
<g:else>
     Year is ${book?.publishYear}
</g:else>

Iterative Tags

You can iterate over collections using the g:each tag.

<g:each in="${author.books}"
    <span class="tag">${it.title}</span>
</g:each>

Or you can name the variable in the each-loop.

<g:each var="b" in="${author.books}"
    <span class="tag">${b.title}</span>
</g:each>

There are also g:while, g:collect and g:findAll tags.

Grails Dynamic Tags

Grails dynamic tags are provided by the Grails tag libraries. You can use them as tags, but you can also call them with methods. This avoids nested tags. For example

<a href="<g:createLink action="list" />" > List </a>

is better written with a method call

<a href="${createLink(action: "list">}"> List </a>

Link Tags

The g:link tag will create an anchor tag. It has the following attributes

  • controller: the controller name for the link
  • action: the action name for the link
  • id: the identifier for the link
  • params: map of parameters to pass to the link.

For example

<g:link controller="book" action="show" id="{$book.id}"> Show Book </g:link>

will create

<a href="/cs4760progassin/book/show/1">Show Book</a>

Using params to generate multiple links.

<g:link controller="book" action="list" params=[max:10,order='title']">Show the first 10 books</g:link>

If you do not specify the controller then it defaults to the current controller. If you do not specify the action then it defaults to the index method.

There is also a url attribute which is map containing controller, action, id and resource. For example linking to the book with id=1.

<g:link url="[controller:'book', action:'show', id='1']"> Show Book</g:link>

But more likely, the view will have a instance of the book, bookInstance, then you can use

<g:link url="[resource:bookInstance, action:'show']" > Show Book</g:link>

Grails will find the id from bookInstance. There are many other attributes, see the reference manual.

http://grails.org/doc/latest/ref/Tags/link.html

Form Tags

The g:form tag has all the attributes of the HTML form tags. They are used the same

<g:form action="save">
 …
</gform>

But you can use all the attributes from the g:link tag if you wish.

<g:form url="[controller='book', action='save']">
 …
</gform>

The g:textField Tag

 <g:form url="[controller='book', action='save']">
     <g:textField name="title" value=""> </g:textField>
 </g:form>

The g:checkBox and g:radio Tages

<g:checkBox name="aBooleanValue" value="${true}" />

and

<fieldset>
    <g:radio name="myGroup" value="friction" checked="${bookInstance.genre = 'fiction'}" /> Fiction </g:radio>
     <g:radio name="myGroup" value="nonfriction" checked="${bookInstance.genre == 'nonfiction'}" /> Nonfiction </g:radio>
 </fieldset>

Select Tag

<g: select name="subject"
 from="${['math', 'cs', 'pyschology', 'humanities']}"
 value="${book.subject}" />

The g:datePicker Tag

<g:datePicker name="date" value="$(new Date()}" precision="day" />

Validation and Error

When a user inputs invalid entries, the errors should be shown in the view for the user to correct.

The hasErrors and eachError Tags

The hasError g-tags test for validation errors. Recall that validation occurs after an attempt to save data. The eachError tag iterates through the errors. Both the hasErrors tag and eachError have three attributes.

  • bean: a bean instance to inspect for errors. This is typically the domain instance.
  • field: the name of the field in the bean to check for errors. This is typically the property of domain instance.
  • model: an alternative to specifying a bean.

The eachError tag is used with the hasError tag.

<g:hasErrors bean="${bookInstance}">
    <ul class="errors">
        <g:eachError bean="${bookInstance}">
            <li>${it.defultMessage}</li>
        </g:eachError>
     </ul>
</g:hasErrors>

A real life example from the book scaffolding.

<g:hasErrors bean="${authorInstance}">
     <ul class="errors" role="alert">
        <g:eachError bean="${authorInstance}" var="error">
             <li <g:if test="${error in org.springframework.validation.FieldError}">
 data-field-id="${error.field}"
                 </g:if>
             >
               <g:message error="${error}"/>
            </li>
      </g:eachError>
    </ul>
</g:hasErrors>

In the example above the “error” attribute in the message tag is the same as the “code” attribute, it just looks in a different file. You should not use the error attribute for your own messages.

Also note how the <g:if-tag is used inside the list tag to make the data-field-id attribute for the list tag. This used by Grails code to locate the entry with the error.

A nice example of modifying the styling of a field is using the hasError method call. See the first line.

<div class="fieldcontain ${hasErrors(bean: authorInstance, field: 'name', 'error')} required">
    <label for="name">
        <g:message code="author.name.label" default="Name" />
        <span class="required-indicator">*</span>
     </label>
    <g:textField name="name" required="" value="${authorInstance?.name}"/>
</div>

The div surrounding has the hasErrors method call. The method call will check authorInstance.name for errors. If there is an error it will output “error” which will add the error class to the div. In this case, the styling will change the border and background.