Show Navigation

Creating your first Grails Application

Learn how to create your first Grails app

Authors: Zachary Klein

Grails Version: 5.0.1

1 Grails Training

Grails Training - Developed and delivered by the folks who created and actively maintain the Grails framework!.

2 Getting Started

In this guide you are going to create your first Grails application. You will learn about domain classes, controllers, services, GSPs, and unit & integration tests. This guide is aimed at developers who are new to Grails or would like a refresher course on the framework.

2.1 What you will need

To complete this guide, you will need the following:

  • Some time on your hands

  • A decent text editor or IDE

  • JDK 1.8 or greater installed with JAVA_HOME configured appropriately

2.2 How to complete the guide

To get started do the following:

or

The Grails guides repositories contain two folders:

  • initial Initial project. Often a simple Grails app with some additional code to give you a head-start.

  • complete A completed example. It is the result of working through the steps presented by the guide and applying those changes to the initial folder.

To complete the guide, go to the initial folder

  • cd into grails-guides/creating-your-first-grails-app/initial

and follow the instructions in the next sections.

You can go right to the completed example if you cd into grails-guides/creating-your-first-grails-app/complete

3 Creating your Grails App

For this guide, you can either create the starting project yourself, or use the initial project included in the guide’s repo to get started. If you choose to use the initial project, you can safely skip this section and continue to [runningTheApp] If you would like to install Grails on your computer, follow one of the options below.

3.1 Installing Grails

Installing Grails

SDKMan

'sdkman' is a popular command line utility for installing and managing Grails installations (as well as other JVM frameworks and languages). Install sdkman by running the following command in your Unix terminal:

$ curl -s "https://get.sdkman.io" | bash

Once the installation is complete, install the latest version of Grails (this guide uses 4.0.1):

$ sdk install grails 4.0.1

sdkman will prompt you to choose whether to set this version as the default (choose 'yes').

$ grails --version

| Grails Version: 4.0.1
| JVM Version: 1.8.0_77
If you are running Windows, there is a clone project of sdkman available that follows the same conventions. You can download it from https://github.com/flofreud/posh-gvm

Download from Grails.org

This is not the recommend way to install Grails, but here are the manual installation steps, if the above methods fails.

Download the Grails binary package from https://grails.org. Unpack the package in a convenient directory.

$ unzip ~/Downloads/grails-4.0.1.zip

Edit your .bashrc (most Linux flavors) or .bash_profile file with the following environment variables (add these to the end of the file)

Set the GRAILS_HOME environment variable to the location where you extracted the zip

export GRAILS_HOME=/path/to/grails-4.0.1

On Windows you can create an environment variable under My Computer/Advanced/Environment Variables

Now add the Grails bin directory to your PATH variable:

export GRAILS_HOME=/path/to/grails-4.0.1
export PATH="$PATH:$GRAILS_HOME/bin

Again, on Windows you will need to modify the Path environment variable under My Computer/Advanced/Environment Variables

You should now be able to type grails -version in the terminal window and verify that Grails has been installed successfully:

$ grails --version

| Grails Version: 4.0.1
| JVM Version: 1.8.0_77

3.2 Grails Application Forge

Did you know you can download a complete Grails project without installing any additional tools? Go to start.grails.org and use the Grails Application Forge to generate your Grails project. You can choose your project type (Application or Plugin), pick a version of Grails, and choose a Profile - then click "Generate Project" to download a ZIP file. No Grails installation necessary!

You can even download your project from the command line using a HTTP tool like curl (see start.grails.org for API documentation):

curl -O start.grails.org/myapp.zip -d version=4.0.1

3.3 Create the App

Creating a Grails app is about as simple as could be - once you have installed Grails, simply run the create-app command:

$ grails create-app myApp

If you don’t specify a package, the app name will be used as the default package for the application (e.g., myapp). You can edit the default package at grails-app/conf/application.yml You can optionally specify a default package for the application:

$ grails create-app org.grails.guides.myApp

3.4 Application Profile

You can optionally specify a Profile for your Grails app. Profiles are available for many common application types, including rest-api, angular, react, and others, and you can even create your own.

To view of a list of what profiles are available, use the list-profiles command.

$ grails list-profiles

| Available Profiles
--------------------
* angular - A profile for creating applications using AngularJS
* rest-api - Profile for REST API applications
* base - The base profile extended by other profiles
* angular2 - A profile for creating Grails applications with Angular 2
* plugin - Profile for plugins designed to work across all profiles
* profile - A profile for creating new Grails profiles
* react - A profile for creating Grails applications with a React frontend
* rest-api-plugin - Profile for REST API plugins
* web - Profile for Web applications
* web-plugin - Profile for Plugins designed for Web applications
* webpack - A profile for creating applications with node-based frontends using webpack

To use a profile, specify its name preceded by the -profile flag:

grails create-app myApp -profile rest-api

You may optionally specify a package and version (defaults to org.grails.profiles and the current version of the profile)

grails create-app myApp -profile org.grails.profiles:react:1.0.2

To get detailed information about a profile use the profile-info command.

$ grails profile-info plugin

Profile: plugin
--------------------
Profile for plugins designed to work across all profiles

Provided Commands:
--------------------
| Error Error occurred loading commands: grails.dev.commands.ApplicationContextCommandRegistry (Use --stacktrace to see the full trace)
| Error Error occurred loading commands: grails.dev.commands.ApplicationContextCommandRegistry (Use --stacktrace to see the full trace)
* package-plugin - Packages the plugin into a JAR file
* publish-plugin - Publishes the plugin to the Grails central repository
* help - Prints help information for a specific command
* open - Opens a file in the project
* gradle - Allows running of Gradle tasks
* clean - Cleans a Grails application's compiled sources
* compile - Compiles a Grails application
* create-command - Creates an Application Command
* create-domain-class - Creates a Domain Class
* create-service - Creates a Service
* create-unit-test - Creates a unit test
* install - Installs a Grails application or plugin into the local Maven cache
* assemble - Creates a JAR or WAR archive for production deployment
* bug-report - Creates a zip file that can be attached to issue reports for the current project
* console - Runs the Grails interactive console
* create-script - Creates a Grails script
* dependency-report - Prints out the Grails application's dependencies
* list-plugins - Lists available plugins from the Plugin Repository
* plugin-info - Prints information about the given plugin
* run-app - Runs a Grails application
* run-command - Executes Grails commands
* run-script - Executes Groovy scripts in a Grails context
* shell - Runs the Grails interactive shell
* stats - Prints statistics about the project
* stop-app - Stops the running Grails application
* test-app - Runs the applications tests

Provided Features:
--------------------
* asset-pipeline - Adds Asset Pipeline to a Grails project
* hibernate4 - Adds GORM for Hibernate 4 to the project
* hibernate5 - Adds GORM for Hibernate 5 to the project
* json-views - Adds support for JSON Views to the project
* less-asset-pipeline - Adds LESS Transpiler Asset Pipeline to a Grails project
* markup-views - Adds support for Markup Views to the project
* mongodb - Adds GORM for MongoDB to the project
* neo4j - Adds GORM for Neo4j to the project
* rx-mongodb - Adds RxGORM for MongoDB to the project
* asset-pipeline-plugin - Adds Asset Pipeline to a Grails Plugin for packaging
When you create an app without -profile the default profile used is the web profile.

4 Running the App

Now that you’ve created (or downloaded) your Grails project, it’s time to run it and see what Grails has already given you.

If you have a local installation of Grails, you can run the app using the run-app command from within your project:

$ cd myApp/

Run the App without Grails Installed

Thanks to the Grails Wrapper, as of Grails version 3.2.3 or later, you can run any Grails command without having Grails installed. If you download it from the Grails Application Forge, the Grails Wrapper is included too.

$ ./grailsw run-app

Run the App with Grails

If you have Grails installed in your machine, simply type:

$ grails run-app

Run the App with Grails Interactive Mode

You can also use Grails' Interactive Mode to run the Grails runtime, from which you can issue any Grails command without waiting for the runtime to spin up for each task.

In this guide we will be preferring the Grails wrapper for most commands.

$ ./grailsw

| Enter a command name to run. Use TAB for completion:
grails>run-app      //you can shutdown the app with the stop-app command

Run the App with Gradle

Finally, because Grails is built upon Spring Boot and Gradle, you can also use Spring Boot commands like bootRun to interact with your Grails application. These commands are available as Gradle tasks. Just as with Grails itself, there’s no need to install Gradle on your machine. It will be downloaded automatically when using the the Gradle Wrapper (gradlew)

$ ./gradlew bootRun

After running any of the above commands, Grails will launch your application using an embedded Tomcat server, and make it available (by default) at http://localhost:8080.

$ ./grailsw run-app

| Running application...
Grails application running at http://localhost:8080 in environment: development

4.1 Change Default Port

If you’d like to change the port number, simply edit the application.yml file under grails-app/conf/, and add the following line:

server:
    port: 8090

You can supply the port number directly in the command invocation:

$ ./grailsw run-app --port=8090

| Running application...
Grails application running at http://localhost:8090 in environment: development

4.2 Auto Reloading

Currently the app simply displays a default index page with some information about the application. The default index page is located under grails-app/views/index.gsp.

Go ahead and edit that file, and change some thing on the page, as shown below (line 54):

    <div id="content" role="main">
        <section class="row colset-2-its">
            <h1>Welcome to My First Grails Project</h1>  (1)
1 Change the text of the <h1> tag.

Save your changes and refresh the page in the browser. You should see your change on the home page. Grails will auto-reload changes to views, controllers, domain classes and other artefacts when it detects changes, so you don’t need to restart the app upon every change.

Major changes to domain class associations, renaming classes, and other operations that affect the "wiring" of the application may not successfully reload.

5 Domain Classes

Grails is a Model View Controller (MVC) framework, based upon the Spring Boot project. Typically an MVC application divides the responsibilities of the app into three categories:

  1. Model - code that defines and manages the data

  2. View - code that manages the presentation of data (e.g, HTML page)

  3. Controller - code that defines the logic of the web application, and manages the communication between the model and the view. Controllers respond to requests, obtain data from the model, and pass it along to the view.

Typically an object-oriented MVC framework requires the developer to configure which classes correspond to each of the three categories above. However, Grails goes farther than most frameworks by following a "Convention over Configuration" approach to development. This means that for many artefact types in Grails (controllers, views, etc), you simply create a file in a particular directory in your project, and Grails will automatically wire it into your application without any additional configuration on your part.

Handling the mapping of domain classes to database tables (and other persistent stores) is the job of GORM, the Grails Object Relational Mapper. GORM is a powerful tool in the Grails framework, and can even be used standalone outside of a Grails project. It supports relational databases (via Hibernate) as well as MongoDb, Neo4j, Redis and Cassandra datasources. Please see the GORM documentation for more information.

When building a MVC application, it is typical to start with the "M" (Model), also known as the "Domain model". In Grails, your domain model is defined with Groovy classes under grails-app/domain. Let’s create a domain class.

5.1 Creating a Domain Class

Domain classes can be generated by Grails (in which case Grails will helpfully create a unit test automatically), or you can simply create the file yourself.

$ ./grailsw create-domain-class Vehicle

| Created grails-app/domain/org/grails/guides/Vehicle.groovy
| Created src/test/groovy/org/grails/guides/VehicleSpec.groovy

This will generate two Groovy files, one being our domain class, and the other a unit test. Let’s see what our domain class looks like.

package org.grails.guides

class Vehicle {

    static constraints = {
    }
}

Right now our domain class has no properties, and no constraints. That’s not very interesting, but it’s worth noting that this is all that’s needed to wire up a persistent domain class in our application. By default, Hibernate will be used to configure a datasource (an in-memory H2 database by default) and create tables and associations for all Groovy classes under grails-app/domain. Let’s add some properties to this domain class:

package org.grails.guides

class Vehicle {

    String name (1)

    String make
    String model

    static constraints = { (2)
        name maxSize: 255
        make inList: ['Ford', 'Chevrolet', 'Nissan']
        model nullable: true
    }
}
1 Properties will be used to create columns in the database (assuming a relational database is used)
2 Constraints are used to enforce valid data in each field - Grails provides a rich set of constraints for common scenarios, and you can define custom constraints as well

Please see the Grails documentation for a complete list and documentation of how to use domain classes and constraints

5.2 DB Console

If you run the app again, you should see the same page as before. However, you can login to the DB Console and view your new database table.

Browse to http://localhost:8080/dbconsole and login. The default username is sa, without a password. The default JDBC URL is: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE

DB Console
You can view the JDBC url in application.yml, under environments development dataSource url

Once you’ve logged in to the DB Console, you should see your new VEHICLES table in the left-hand sidebar. Click the + icon to expand the table - you should see a list of columns, including the three String fields we just defined, name, make, and model.

DB Console

5.3 Expanding the Domain Model

For our Vehicle class, it doesn’t really make sense that make and model are plain Strings, since models should actually be associated with makes. Let’s update our domain model to be more robust.

Create two new domain classes:

$ ./grailsw create-domain-class Make

| Created grails-app/domain/org/grails/guides/Make.groovy
| Created src/test/groovy/org/grails/guides/Make.groovy

$ ./grailsw create-domain-class Model

| Created grails-app/domain/org/grails/guides/Model.groovy
| Created src/test/groovy/org/grails/guides/Model.groovy

Edit these two files with the following content:

grails-app/domain/org/grails/guides/Make.groovy
package org.grails.guides

class Make {

    String name

    static constraints = {
    }

    String toString() {
        name
    }
}
grails-app/domain/org/grails/guides/Model.groovy
package org.grails.guides

class Model {

    String name

    static belongsTo = [ make: Make ]

    static constraints = {
    }

    String toString() {
        name
    }
}
The belongsTo property is one of several properties that GORM uses to determine associations between domain classes. Others include hasMany and hasOne. For more information please see the GORM documentation.

Now, update Vehicle.groovy to use the new Make and Model classes instead of String.

grails-app/domain/org/grails/guides/Vehicle.groovy
package org.grails.guides

@SuppressWarnings('GrailsDomainReservedSqlKeywordName')
class Vehicle {

    Integer year

    String name
    Model model
    Make make

    static constraints = {
        year min: 1900
        name maxSize: 255
    }
}

Grails (via GORM) will now create three tables in our database, for our three domain classes, and create the necessary associations between the tables. Run the app again and open the DB Console to view the new tables.

5.4 Bootstrapping Data

Every Grails project includes a BootStrap.groovy file under grails-app/init. This file can be used for any custom logic you want to happen during application startup. One excellent use of the file is to preload some data in our database. Let’s create a few instances of our three domain classes.

Edit grails-app/init/org/grails/guides/BootStrap.groovy, as shown below:

grails-app/init/org/grails/guides/BootStrap.groovy
package org.grails.guides

import groovy.transform.CompileStatic

@CompileStatic
class BootStrap {

    MakeService makeService
    ModelService modelService
    VehicleService vehicleService
    def init = { servletContext ->

        Make nissan = makeService.save('Nissan')
        Make ford = makeService.save( 'Ford')

        Model titan = modelService.save('Titan', nissan)
        Model leaf = modelService.save('Leaf', nissan)
        Model windstar = modelService.save('Windstar', ford)

        vehicleService.save('Pickup', nissan, titan, 2012).save()
        vehicleService.save('Economy', nissan, leaf, 2014).save()
        vehicleService.save('Minivan', ford, windstar, 1990).save()
    }
    def destroy = {
    }
}

Now restart the application, and browse to the DBConsole, you should be able to expand the three tables and see our newly created data.

5.5 Datasources

By default, Grails configures an in-memory H2 database, which is dropped and recreated every time the app is restarted. This will be sufficient for our purposes in this guide, however, you can easily change this to a local database instance by configuring your own datasource. We’ll use MySQL as an example.

5.6 Configure MySQL Datasource

Edit build.gradle

build.gradle
dependencies {
    //...

    runtime 'mysql:mysql-connector-java:5.1.40' (1)
1 Add the MySQL JDBC driver as a dependency
Be sure to add the dependency to the dependencies section of the build.gradle file, and not the buildscript/dependencies section. The former is for application dependencies (needed at compile time, runtime, or for testing), whereas the buildscript dependencies is for those needed as part of the Gradle build process (managing static assets, for example).

Edit application.yml

grails-app/conf/application.yml
dataSource:
    pooled: true
    jmxExport: true
    driverClassName: com.mysql.jdbc.Driver   (1)
    dialect: org.hibernate.dialect.MySQL5InnoDBDialect
    username: sa
    password: testing
environments:
    development:
        dataSource:
            dbCreate: update
            url: jdbc:mysql://127.0.0.1:3306/myapp  (2)
1 Change the driverClassName and dialect to MySQL settings
2 This assumes you have a local MySQL instance with a database named myapp

5.7 Grails Console

Right now we don’t have any controllers or views set up to play with our domain model. We’ll get there shortly, but for now, let’s fire up the Grails Console so we can explore what Grails and GORM have to offer.

If the application is still running, shut it down with either kbd:[Ctrl+C], or (if running Grails in Interactive Mode, the stop-app command).

Launch the Grails Console:

$ ./grailsw console

The Grails Console application will launch. This application is based on the Groovy Console, but has the added benefit that our entire Grails application is up and running in the background, so we can access our domain classes and even persist to the database from the Console.

Try playing with our new domain model from the Console. Here’s a simple script to get you started - again, refer to the GORM documentation for more details on querying, persistence, configuration and more.

docs/console.groovy
import org.grails.guides.*

def vehicles = Vehicle.list()

println vehicles.size()

def pickup = Vehicle.findByName("Pickup")

println pickup.name
println pickup.make.name
println pickup.model.name

def nissan = Make.findByName("Nissan")

def nissans = Vehicle.findAllByMake(nissan)

println nissans.size()

6 Controllers

This section will focus on the basics of creating a controller and defining actions.

While not part of the "MVC" triad, Grails also provides support for services. In a Grails application of any complexity, it is considered best practice to keep core application logic in services. We’ll get to services later on in this guide.

Following the convention over configuration principle, Grails will configure any Groovy classes under grails-app/controllers/ as controllers, without any additional configuration. You can create the Groovy class yourself, or use the create-controller command to generate the controller and an associated test spec.

$ ./grailsw create-controller org.grails.guides.Home

| Created grails-app/controllers/org/grails/guides/HomeController.groovy
| Created src/test/groovy/org/grails/guides/HomeControllerSpec.groovy
Note that Grails adds the *Controller suffix automatically.

Let’s take a look at our new controller.

grails-app/controllers/org/grails/guides/HomeController.groovy
package org.grails.guides

class HomeController {

    def index() { }
}

Grails has created a controller with a single action. Actions are public methods in a controller, which can respond to requests. Typically, a controller action will receive a request, obtain some data (optionally using parameters or a body of the request, if present), and render the result to the browser (e.g, as a webpage). Controller actions can also redirect requests, forward, call service methods, and return HTTP response codes. See the Grails documentation for more on controller actions.

We don’t have any need for logic in this particular action just yet, but we would like it to render a page. We’ll look at GSP pages in more detail in the [Views] section, but for now, let’s create a very simple GSP page for our HomeController.index action to display.

Create the file index.gsp under the grails-app/views/home directory.

grails-app/views/home/index.gsp
<html>
<html>
<head>
    <meta name="layout" content="main"/>
    <title>Home Page</title>
</head>
<body>

<div id="content" role="main">
    <section class="row colset-2-its">
        <h1>Welcome to our Home Page!</h1>
    </section>
</div>

</body>
</html>

Run the application again and browser to http:localhost:8080/home. You should see your new page.

By convention, Grails will map controller actions to views with the same name, in the grails-app/views/[controller name] directory. You can override this and specify a particular view (or render different content altogether).

We’ll cover views and GSPs in more detail in the next section, but for now, you should note that our index.gsp file is basically an HTML page, with a couple unusual tags. Feel free to modify this new home page however you would like.

6.1 URL Mappings

Now that we have our new "home" page, it would be nice if it was the app’s landing page instead of the Grails default. To do that, we’ll need to change our UrlMappings.groovy file.

Grails uses the UrlMappings.groovy file to route request to the proper controller and action. They can be as simple as URI strings that redirect to a controller and/or action, or they can include wildcards and constraints and become quite sophisticated.

Learn much more about URL Mappings from the Grails documentation

Let’s look at the default URLMappings.groovy file.

grails-app/controllers/org/grails/guides/UrlMappings.groovy
package org.grails.guides

class UrlMappings {

    static mappings = {
        "/$controller/$action?/$id?(.$format)?"{  (1)
            constraints {
                // apply constraints here
            }
        }

        "/"(view:"/index")   (2)
        "500"(view:'/error')
        "404"(view:'/notFound')
    }
}
1 Grails default URL mapping - this rule causes requests to be mapped to controller and action (and optionally ID and/or format) based on names. So home/index will map to HomeController, index action
2 This URL mapping points the root URI (/) to a specific view.

Let’s change the / rule to point to our new HomeController. Edit the line as follows:

grails-app/controllers/org/grails/guides/UrlMappings.groovy
package org.grails.guides

class UrlMappings {

    static mappings = {
//...

        "/"(controller:"home")   (1)
//...
    }
}
1 Change view: "/index" to controller: "home"

By convention, a request to a controller without an action name will go to an index action, if it exists (if not, an error will be thrown). You can change this behavior if you want by specifying a defaultAction property in the controller:

grails-app/controllers/org/grails/guides/HomeController.groovy
package org.grails.guides

class HomeController {

    static defaultAction = "homePage"

    def homePage() { } (1)
}
1 Don’t make this change, this is just for demonstration purposes

Now that you’ve changed the / rule to point to your new HomeController, if you restart the app and browser to http://localhost:8080, you should be presented with your new home page.

6.2 Scaffolding

We’d like to have actions to allow us to create new domain class instances and persist them to the database. In addition, we’d like to have the ability to edit existing instances and even delete them. Normally all this functionality would require a lot of coding, but Grails gives us a headstart with scaffolding.

Learn more about scaffolding in the Grails documentation.

6.3 Dynamic Scaffolding

Now that we have a home page, let’s create controllers to manage the domain model we created earlier. Create 3 new controllers for each of the domain classes, Vehicle, Make, and Model.

$ ./grailsw create-controller Vehicle

| Created grails-app/controllers/org/grails/guides/VehicleController.groovy
| Created src/test/groovy/org/grails/guides/VehicleControllerSpec.groovy

$ ./grailsw create-controller Make

| Created grails-app/controllers/org/grails/guides/MakeController.groovy
| Created src/test/groovy/org/grails/guides/MakeControllerSpec.groovy

$ ./grailsw create-controller Model

| Created grails-app/controllers/org/grails/guides/ModelController.groovy
| Created src/test/groovy/org/grails/guides/ModelControllerSpec.groovy

To use scaffolding, edit the three controllers we just created, and replace the default index action with a scaffolding property as shown in the examples below.

grails-app/controllers/org/grails/guides/VehicleController.groovy
package org.grails.guides

class VehicleController {

    static scaffold = Vehicle
}
grails-app/controllers/org/grails/guides/MakeControler.groovy
package org.grails.guides

class MakeControler {

    static scaffold = Make
}
grails-app/controllers/org/grails/guides/ModelController.groovy
package org.grails.guides

class ModelController {

    static scaffold = Model
}

With the scaffold property set, Grails will now generate all necessary CRUD (Create, Read, Update, Delete) actions for the respective domain classes. It will also dynamically generate views with list, create, show and edit pages using our domain properties and associations. This can give you a big leg up when putting together the beginnings of an application.

Restart the app, and browse to http://localhost:8080/vehicle - you should see a list of the Vehicle instances we added to our BootStrap. Try out the new views and create, view, edit and delete some instances. You can also do the same with the Model and Make controllers.

6.4 Static Scaffolding

Dynamic scaffolding is powerful and sometimes will provide all the functionality you need (especially for an administrative site where data access is more important than presentation). But it’s quite likely that you will feel the need to customize the generated views and controllers, either to change their appearance or to add custom logic and functionality. Grails anticipates this need and provides a set of generate commands that can generate the controllers and/or views that you just saw, allowing you to modify them to suite your needs.

To generate the views (and continue to use the dynamic scaffolding):

$ ./grailsw generate-views Vehicle

To generate the controller (and continue to use the dynamic GSP views):

$ ./grailsw generate-controller Vehicle

To both views and controllers (bypassing all dynamic generation):

$ ./grailsw generate-all Vehicle

The generated controller will be placed under grails-app/controller, and the generated views will be placed under grails-app/views/vehicle.

To override existing files, use th -force flag along with the generate-* command: ./grailsw generate-all com.example.Vehicle -force

Let’s generate the controller and views for Vehicle and take a look at the resulting controller.

$ ./grailsw generate-all Vehicle -force

Open the VehicleController.groovy file at grails-app/controllers/org/grails/guides/.

import static org.springframework.http.HttpStatus.NOT_FOUND
import static org.springframework.http.HttpStatus.OK
import static org.springframework.http.HttpStatus.CREATED
import org.grails.guides.Vehicle
import grails.gorm.transactions.Transactional

@SuppressWarnings(['LineLength'])
@ReadOnly (1)
class VehicleController {

    static namespace = 'scaffolding'

    static allowedMethods = [save: 'POST', update: 'PUT', delete: 'DELETE']

    def index(Integer max) {
        params.max = Math.min(max ?: 10, 100) (2)
        respond Vehicle.list(params), model:[vehicleCount: Vehicle.count()] (3)
    }

    def show(Vehicle vehicle) {
        respond vehicle (3)
    }

    @SuppressWarnings(['FactoryMethodName', 'GrailsMassAssignment'])
    def create() {
        respond new Vehicle(params) (3)
    }

    @Transactional (1)
    def save(Vehicle vehicle) {
        if (vehicle == null) {
            transactionStatus.setRollbackOnly()
            notFound()
            return
        }

        if (vehicle.hasErrors()) {
            transactionStatus.setRollbackOnly()
            respond vehicle.errors, view:'create'  (3)
            return
        }

        vehicle.save flush:true

        request.withFormat {  (4)
            form multipartForm {
                (5)
                flash.message = message(code: 'default.created.message', args: [message(code: 'vehicle.label', default: 'Vehicle'), vehicle.id])
                redirect vehicle
            }
            '*' { respond vehicle, [status: CREATED] } (3)
        }
    }

    def edit(Vehicle vehicle) {
        respond vehicle (3)
    }

    @Transactional (1)
    def update(Vehicle vehicle) {
        if (vehicle == null) {
            transactionStatus.setRollbackOnly()
            notFound()
            return
        }

        if (vehicle.hasErrors()) {
            transactionStatus.setRollbackOnly()
            respond vehicle.errors, view:'edit' (3)
            return
        }

        vehicle.save flush:true

        request.withFormat {
            form multipartForm {
                (5)
                flash.message = message(code: 'default.updated.message', args: [message(code: 'vehicle.label', default: 'Vehicle'), vehicle.id])
                redirect vehicle (6)
            }
            '*' { respond vehicle, [status: OK] } (3)
        }
    }

    @Transactional (1)
    def delete(Vehicle vehicle) {

        if (vehicle == null) {
            transactionStatus.setRollbackOnly()
            notFound()
            return
        }

        vehicle.delete flush:true

        request.withFormat {
            form multipartForm {
                (5)
                flash.message = message(code: 'default.deleted.message', args: [message(code: 'vehicle.label', default: 'Vehicle'), vehicle.id])
                redirect action: 'index', method: 'GET' (6)
            }
            '*' { render status: NO_CONTENT } (7)
        }
    }

    protected void notFound() {
        request.withFormat {
            form multipartForm {
                (5)
                flash.message = message(code: 'default.not.found.message', args: [message(code: 'vehicle.label', default: 'Vehicle'), params.id])
1 The @Transactional annotation configures the transactional behavior of the controller or method. Transactions are used to manage persistence and other complicated operations that should be completed together (and potentially rolled-back if any one of the steps fails). For more information on transactions, see the Grails documentation
2 The params object is available to all controllers, and contains a map of any URL parameters on the request. You can refer to any parameter by name to retrieve the value: params.myCustomParameter will match this URL parameter: [url]?myCustomParameter=hello. See the Grails documentation for more detail.
3 The respond method takes an object to return to the requestor, using content negotiation to choose the correct type (for example, a request’s Accept header might specify JSON or XML). respond also can accept a map of arguments, such as model (which defines the way the data is loaded on a page). For more on how to use the respond method, see the Grails documentation.
4 request is available on all controllers, and is an instance of the Servlet API’s HttpServletRequest class. You can access request headers, store properties in the request scope, and get information about the requestor using this object. For more see the Grails documentation on request.
5 flash is a map that stores objects within the session for the next request, automatically clearing them after that next request completes. This is useful for passing error messages or other data that you want the next request to access. For more, see the Grails documentation on flash.
6 The redirect method is a simple one - it allows the action to redirect the request to another action, controller, or a URI. You can also pass along parameters with the redirect. See the Grails documentation on redirect for more.
7 The render method is a less sophisticated version of respond - it doesn’t perform content negotiation, so you have to specify exactly what you want to render. You can render plain text, a view or template, an HTTP response code, or any object that has a String representation. See the Grails documentation.

That’s a lot of code! Generating and modifying a scaffold controller is a good learning exercise, so feel free to experiment and modify this code - you can always revert back to the version in the completed project of this guide.

6.5 Render a response

Let’s modify our HomeController to render some custom content on our home page. Edit grails-app/controllers/org/grails/guides/HomeController.groovy.

grails-app/controllers/org/grails/guides/HomeController.groovy
package org.grails.guides

class HomeController {

    def index() {
        respond([name: session.name ?: 'User', vehicleTotal: Vehicle.count()]) (1)
    }

    def updateName(String name) {
        session.name = name (2)

        flash.message = "Name has been updated" (3)

        redirect action: 'index' (4)
    }

}
1 We’re calling the respond method to render a Groovy map of content to the requestor, containing a name property from the session (defaulting to "User" if no session value exists) and the current total of Vehicle instances from GORM’s count method.
2 session is an instance of the Servlet API’s`HttpSession` class, and is available in every controller. We can retrieve and store properties in the session - in this case, we’re storing a String with the attribute name in the session. For more see the Grails documentation.
3 We’re using flash scope to set a message to display upon the next request
4 We don’t have any specific content to display in this action, so we issue a redirect back to the index action (note that in Groovy method parenthesis are optional so long as there is at least one argument).

We’ve updated our index action to render some custom content to the page, and we’ve created a new action updateName, which takes a String parameter and saves it to the session for later retrieval. However, we need to update our view to 1. display the newly available content, and 2. provide some means of calling updateName and setting the session attribute.

Edit grails-app/views/home/index.gsp:

grails-app/views/home/index.gsp
<html>
<html>
<head>
    <meta name="layout" content="main"/>
    <title>Home Page</title>
</head>
<body>

<div id="content" role="main">
    <section class="row colset-2-its">
        <h1>Welcome ${name}!</h1> (1)

        <h4>${flash.message}</h4>  (2)

        <p>There are ${vehicleTotal} vehicles in the database.</p> (1)

        <form action="/home/updateName" method="post" style="margin: 0 auto; width:320px"> (3)
            <input type="text" name="name" value="" id="name">
            <input type="submit" name="Update name" value="Update name" id="Update name">
        </form>

    </section>
</div>

</body>
</html>
1 We can refer to any values in our "model" by name in a GSP page, using Groovy String Expressions ${name} ${vehicleTotal}
2 Here we’re accessing our flash.message property - if it’s null then nothing will render here.
3 This is a plain HTML form that will submit the name text field to the updateName action we just created.

Run the app and you should see our new message in the <h1> header: "Welcome User!", as well as the current total of Vehicle instances in the database.

Try entering your own name in the form and submitting it - you should see the page reload and your own name will replace "User". Refresh the page a few times. Because we stored the name in the session, it will persist as long as the session is valid.

Content Negotiation

Remember we used the respond method, instead of the simpler render method to send our "model" to the page. This means we can get our model using other formats besides an HTML page, such as JSON or XML.

Run the following command in a terminal (while the app is running)

$ curl -i -H "Accept: application/json" "http://localhost:8080/home/index"

HTTP/1.1 200
X-Application-Context: application:development
Set-Cookie: JSESSIONID=008B45AAA1A820CE5C9FDC2741D345F3;path=/;HttpOnly
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 11 Jan 2017 04:06:57 GMT

{"name":"User","vehicleTotal":3}

We’ve used curl to call our index action, but we’ve changed our Accept header to application/json. Now instead of an HTML page, we receive the same data in JSON.

You can request difference content types in the browser as well, thanks to Grails' default URL Mappings (shown below):

grails-app/controllers/org/grails/guides/UrlMappings.groovy
        "/$controller/$action?/$id?(.$format)?" {
            constraints {
                // apply constraints here
            }
        }

Note the (.$format)? token in the mapping. This will match a suffix on our URL such as .json or .xml. Test this out in your browser.

Browse to http://localhost:8080/home/index.json. You should see the same JSON body we retrieved using curl.

Try changing .json to .xml. You should see an XML representation of the model. Content negotiation allows your controllers to be very versatile and to return appropriate data to different clients from the same actions.

7 Views

Views are the third component of the MVC pattern. Views are responsible for presenting data to the user (which might be a browser page, an API endpoint, or some other sort of consumer). In many apps, views are HTML pages designed to be loaded in a browser. However, it is perfectly reasonable for a "view" to be an XML or JSON document, depending on the type of client requesting the view.

Grails' primary view technology is Groovy Server Pages. It follows many of the conventions of JSP and ASP, but naturally it is based upon the Groovy language. GSP pages are essentially HTML documents, but they support a number of special tags (typically prefix with g:) to allow programmatic control over your views. You can even write arbitrary Groovy code in your GSP pages, but this is strongly discouraged - ideally, the GSP page should only contain view-related logic and content; any sort of data manipulation or processing should happen in the controller (or in a service) prior to the view being rendered.

You’ve already worked with GSP views in this guide, but let’s quickly cover the basics.

Layouts

GSP views in an application often need to share some general structure, and perhaps some shared assets like JavaScript files. Grails uses the SiteMesh templating technology to support the idea of "layouts", which are essentially GSP template files that your GSP page can "inherit".

By convention, layouts are located under grails-app/views/layouts. Grails includes a main.gsp template in the default project, and that’s the one that Grails scaffolding uses, as well as the default home page. We’re using it as well. To use a GSP layout, simply specify the name of the layout using a <meta name="layout"> tag:

<html>
<html>
<head>
    <meta name="layout" content="main"/>
</head>
<!-- ... -->

You can create your own layouts as well. Let’s create a new layout for our home page.

$ vim grails-app/views/layouts/public.gsp

Edit your new layout. We’ll be copying the existing main.gsp as a start, but we’ll add a custom logo image and remove some layout code we don’t need on our pages.

grails-app/views/layouts/public.gsp
<!doctype html>
<html lang="en" class="no-js">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>
        <g:layoutTitle default="Auto Catalog"/>
    </title>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>

    <asset:stylesheet src="application.css"/>

    <g:layoutHead/>
</head>
<body>

<div class="navbar navbar-default navbar-static-top" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <a class="navbar-brand" href="/#">
                <i class="fa grails-icon">
                    <asset:image src="logo.png"/>
                </i> Auto Catalog
            </a>
        </div>
        <div class="navbar-collapse collapse" aria-expanded="false" style="height: 0.8px;">
            <ul class="nav navbar-nav navbar-right">
                <g:pageProperty name="page.nav" />
            </ul>
        </div>
    </div>
</div>

<g:layoutBody/>

<div class="footer" role="contentinfo"></div>

</body>
</html>

The key points of this layout are the <g:layoutBody> and <g:layoutHead> tags. These tags are substituted by SiteMesh for the <head> and <body> sections of any GSP page that uses the layout.

Feel free to provide your own logo.png image, or use the one from the completed project (or download at this link). Place the image in the grails-app/assets/images/ directory, and the layout should render it instead of the Grails logo.
Don’t worry about the <asset> tags in the new layout just yet - we’ll be covering those shortly.

Now edit the home/index.gsp view to use the new public layout.

grails-app/views/home/index.gsp
<html>
<head>
    <meta name="layout" content="public"/> (1)
    <title>Home Page</title>
1 Change "main" to "public"

Refresh the page (or restart the app) and you should see the new layout in action. Feel free to modify the public.gsp layout further if you wish.

7.1 Views Resolution

How does Grails choose which view to render? By convention, Grails looks for views under the grails-app/views directory. It will attempt to resolve views to controller actions by matching the controller name with a directory under the views directory. E.g., HomeController will resolve to grails-app/views/home. Grails will then map actions to GSP pages with the same name. E.g, index will resolve to index.gsp.

You can also render a particular view from your controller action (overriding Grails' conventions) using the render method:

class SomeController {
    def someAction() {
        render view: 'anotherView'
    }
}

This will attempt to resolve to a anotherView.gsp page under grails-app/views/some/. If you would like to resolve a view that is not under the controller’s own view directory, use a leading / to specifiy an absolute path from grails-app/views:

class SomeController {
    def someAction() {
        render view: '/another/view'
    }
}

This will resolve to view.gsp under grails-app/views/another/.

7.2 GSP

GSP pages have access to a rich set of tags. We’ve seen a few in action already. You can get much more detail on the available GSP tags (including how to define your own custom tags) from the Grails documentation.

Let’s soup up our index.gsp page a bit with some GSP tags.

Edit grails-app/views/home/index.gsp

grails-app/views/home/index.gsp
<%@ page import="Vehicle" %>
<html>
<head>
    <meta name="layout" content="public"/>
    <title>Home Page</title>
</head>
<body>

<div id="content" role="main">
    <section class="row colset-2-its">
        <h1>Welcome ${name}!</h1>
        <g:if test="${flash.message}"> (1)
            <div class="message" role="status">${flash.message}</div>
        </g:if>

        <p>There are ${vehicleTotal} vehicles in the database.</p>

        <ul>
        <g:each in="${Vehicle.list()}" var="vehicle">
            <li>
                <g:link controller="vehicle" action="show" id="${vehicle.id}">
                    ${vehicle.name} - ${vehicle.year} ${vehicle.make.name} ${vehicle.model.name}
                </g:link>
            </li>
        </g:each>
        </ul>

        <g:form action="updateName" style="margin: 0 auto; width:320px"> (2)
            <g:textField name="name" value="" />
            <g:submitButton name="Update name" />
        </g:form>

    </section>
</div>

</body>
</html>
1 Rather than rendering flash.message regardless of whether it exists, we use the <g:if> tag to test if there is a message, and then render the message (using some custom styling).
2 Replace the plain HTML <form> tags with their GSP equivalents.

Let’s take a closer look at <g:if>.

    <g:if test="${isThisTrue}}>
        Some content
    </g:if>

GSP tags can optionally accept attributes, such as test in this example. Different tags require different types of attributes, but typically you will end up passing a Groovy Expression like in this example. Any Groovy code between the ${ and } will be evaluated (on the server) and the result will be substituted on the rendered page.

You can use Groovy Expressions anywhere on the GSP page, not just in tags. See the ${flash.message} in our index.gsp page.

Other tag attributes might accept plain strings or numbers. E.g, <g:form action="updateName">

A GSP tag can also optionally include a body. In the case of <g:if>, the body will only be rendered if the test expression evaluates to true (following the Groovy Truth convention). Other GSP tags (like <g:form>) simply include the body within the resulting HTML output.

7.3 GSP Tags Iteration

Iteration

There are GSP tags for iteration as well - a very useful one is <g:each>. Let’s try it out:

grails-app/views/home/index.gsp
<%@ page import="Vehicle" %> (1)
<html>
<!-- ... -->
        <p>There are ${vehicleTotal} vehicles in the database.</p>

        <ul>
            <g:each in="${Vehicle.list()}" var="vehicle">  (2)
                <li>
                    <! -- ... -->
                </li>
            </g:each>
        </ul>

<!-- ... -->

The <g:each> tag iterates through a collection of objects, provided by the in attribute. var sets the name for each object in the collection. Grails will iterate through the collection (in this case, the list of Vehicles returned by Vehicle.list()) and render the body of the <g:each> tag for every item.

1 This is a JSP-style expression that allows executing arbitrary Groovy code (without rendering a result). We’re using it here to import our Vehicle class. This is highly discouraged - we’ll explain why shortly.
2 Bad practice, accessing the Domain model directly from the view
This sort of code is a bad idea - we are accessing our domain model (Vehicle) directly from our view, which tightly couples two separate parts of the application, and in general leads to very messy code. The better way to accomplish this feature is to get the Vehicle list in the HomeController.index action, and add the list to our model object (the one being passed to respond). Then we could refer to the list in the same way that we access name and vehicleTotal. Go ahead and change the controller and view to use this better approach - the completed project has this change already made if you need help.

Let’s take a look at one more common GSP tag: <g:link>

grails-app/views/home/index.gsp
        ${vehicle.name} - ${vehicle.year} ${vehicle.make.name} ${vehicle.model.name}
    </g:link>
</li>

<g:link> renders an HTML <a> tag, but it has the advantage in that it allows you to specify your link target following Grails conventions, such as this example (using the controller, action and id attributes). <g:link> is also smart enough to follow our URL mappings, so if we change the URL mapping for vehicle/show, the <g:link> tag will still render the correct URL. There’s many more attributes supported by <g:link> - see the Grails documentation for more.

7.5 Asset Pipeline

You may have noticed a few <asset> tags in our GSP pages. These tags are provided by the Asset Pipeline plugin, which is Grails' default tool for managing static assets (images, CSS, JavaScript files, etc). The Asset Pipeline plugin provides a set of custom GSP tags, but unlike the tags we’ve been exploring, it uses the asset prefix (or namespace).

The most common <asset> tags are listed below:

<asset:javascript src="myscript.js" /> (1)

<asset:image src="myimage.png" /> (2)

<asset:stylesheet src="mystyles.css" /> (3)
1 This tag loads JavaScript files from grails-app/assets/javascripts
2 This tag loads images from grails-app/assets/images
3 This tag loads CSS files from grails-app/assets/stylesheets

As you can see, the Asset Pipeline follows a convention over configuration approach, following the precedent of Grails. However, Asset Pipeline is a very powerful framework, and includes a rich plugin ecosystem - you can find plugins to render LESS and SASS files, CoffeeScript, Ember, Angular, JSX (React), and more.

Asset Pipeline also supports minification and compression of your assets, and much more.

Visit asset-pipeline.com for much more information on using the Asset Pipeline, including a directory of available plugins.

7.6 Add Javascript Asset

Let’s use the Asset Pipeline plugin to add jQuery to our page. Grails includes jQuery by default. The version of Grails used in this guide included jQuery 2.2.0 by default:

_grails-app/assets/javascripts/jquery-2.2.0.min.js_

but let’s instead download the latest version. Download jQuery from https://code.jquery.com/jquery-3.1.1.js

Save jquery-3.1.1.js to grails-app/assets/javascripts.

Edit grails-app/views/home/index.gsp, add the following snippet in the head block.

grails-app/views/home/index.gsp
<asset:javascript src="jquery-3.1.1.js" />

<script type="text/javascript">
  $( document ).ready(function() {
    console.log( "jQuery 3.1.1 loaded!" );
  });
</script>

Refresh the page, and open your browser’s developer console. You should see the string jQuery 3.1.1 loaded! in the console logs.

8 Services

Grails provides a "service layer", which are classes that encapsulate business logic and are wired (using dependency injection) into the application context, so that any controller can inject and use them. Services are the preferred vehicle for most application logic, not controllers.

If this seems confusing, think of it this way: controllers are intended to respond to the request and return a response. Services can be reused across many controllers (as well as in domain classes and from other services). Services are more versatile and can help you keep your controllers clean and prevent duplication of business logic. It is often easier to write unit tests against service methods than against controller actions, as well.

Controllers are for "web logic", services for "business logic"

Again by convention, Grails will configure any Groovy classes within the grails-app/services directory as services. Services will be "wired" as Spring beans in the Grails application context, which means you can refer to them simply by name from any other Spring bean (including controllers and domain classes).

Let’s add a feature to generate an estimated value for Vehicle, based on the make, model and year. We’ll put this logic in a service and call it from our application code.

Create a new service using the create-service Grails command:

$ ./grailsw create-service ValueEstimateService

| Created grails-app/services/org/grails/guides/ValueEstimateService.groovy
| Created src/test/groovy/org/grails/guides/ValueEstimateServiceSpec.groovy

Edit grails-app/services/org/grails/guides/ValueEstimateService.groovy

grails-app/services/org/grails/guides/ValueEstimateService.groovy
package org.grails.guides

import grails.gorm.transactions.Transactional

@Transactional
class ValueEstimateService {

    def serviceMethod() {

    }
}

Grails has provided a serviceMethod stub as an example. Delete it and replace it with the following content:

grails-app/services/org/grails/guides/ValueEstimateService.groovy
package org.grails.guides

import grails.gorm.transactions.Transactional

@Transactional
class ValueEstimateService {

    def getEstimate(Vehicle vehicle) {
        log.info 'Estimating vehicle value...'

        //TODO: Call third-party valuation API
        Math.round (vehicle.name.size() + vehicle.model.name.size() * vehicle.year) * 2
    }
}

Obviously this method of estimating a vehicle’s value is pretty contrived! In reality you would likely call a third-party webservice to get a valuation, or perhaps run a query against your own database. However, the point of this example is to show the sort of "business logic" that can be placed in services, rather than being calculated within a controller or view.

Now, let’s use our new service.

Edit grails-app/controllers/org/grails/guides/VehicleController.groovy (the scaffolded controller we generated earlier), and add the property shown below:

grails-app/controllers/org/grails/guides/VehicleController.groovy
static namespace = 'scaffolding'
1 By simply defining a property in our controller with the same name as our service class, Grails will inject a reference to the service for us.

Now (still editing VehicleController.groovy), modify the show action as seen below:

grails-app/controllers/org/grails/guides/VehicleController.groovy
}

def show(Vehicle vehicle) {

We’ve added a new property to the model, called estimatedValue. The value of this property is the result of calling our service method, getEstimate, to which we pass the vehicle property we are about to render.

Now, on the show page, we can access the estimatedValue property and display it on the page. Edit grails-app/views/vehicle/show.gsp as shown below:

grails-app/views/vehicle/show.gsp
<div id="show-vehicle" class="content scaffold-show" role="main">
    <h1><g:message code="default.show.label" args="[entityName]" /></h1>
    <h1>Estimated Value: <g:formatNumber number="${estimatedValue}" type="currency" currencyCode="USD" /></h1>

Restart the application and browse to the show page for a Vehicle, such as http://localhost:8080/vehicle/show/1. You should see the "Estimated Value" on the page

9 Testing your App

Testing is a vital part of web application development. Grails provides support for three types of testing: unit tests, integration tests, and functional tests. Unit tests are usually the simplest kind, focusing on a specific piece of code without depending on other parts of your app. Integration tests require the Grails environment to be up and running, and are used to test features that depend on database or network resources. Functional tests require the app to be running, and are designed to exercise the application almost as a user would, by making HTTP requests against it. These tend to be the most complex tests to write.

The testing framework used by Grails is Spock. Spock provides an expressive syntax for writing test cases, based on the Groovy language, and so is a great fit for Grails. It includes a JUnit runner, which means IDE support is effectively universal (any IDE that can run JUnit tests can run Spock tests).

Spock is a rich framework (even outside of Grails applications) and well worth your time to master, if you haven’t already. Check out the extensive documentation for an introduction to Spock.

Grails tests are stored (by convention) in the src/test/groovy directory (unit tests) and src/integration-test/groovy directory (integration/functional tests).

You can run your Grails tests using the test-app command:

$ ./grailsw test-app

If you want to run only unit tests or integration/functional tests, you can pass in a command line flag to choose one or the other.

$ ./grailsw test-app -unit
$ ./grailsw test-app -integration

You can also run a specific test by passing the test class as an argument:

$ ./grailsw test-app org.grails.guides.MyTestSpec

Writing tests is a very broad topic and worthy of its own guide. In practice, the simplest (and often most useful) tests are unit tests, so let’s write a simple unit test to exercise our ValueEstimateService.

Grails automatically creates a test spec for services created with the create-service command. Open src/test/groovy/org/grails/guides/ValueEstimateServiceSpec.

src/test/groovy/org/grails/guides/ValueEstimateServiceSpec
package org.grails.guides

import grails.testing.gorm.DataTest
import grails.testing.services.ServiceUnitTest
import spock.lang.Specification

class ValueEstimateServiceSpec extends Specification implements ServiceUnitTest<ValueEstimateService>, DataTest {

    def setup() {
    }

    def cleanup() {
    }

    void "test something"() {
        expect:"fix me"
            true == false
    }
}

Currently our test spec has one test, "test something", which asserts that true == false. Grails is helpfully encouraging you to do the right thing by kicking things off with a failing test.

Try running the test, just to confirm it fails:

$ /grailsw test-app org.grails.guides.ValueEstimateServiceSpec

...
> There were failing tests. See the report at: file:///Users/dev/projects/creating-your-first-grails-app/complete/build/reports/tests/test/index.html

BUILD FAILED

Total time: 6.353 secs
| Tests FAILED Test execution failed

Now that we’ve confirmed our test is failing, let’s edit this test case to exercise our getEstimate method. Edit src/test/groovy/org/grails/guides/ValueEstimateServiceSpec.

src/test/groovy/org/grails/guides/ValueEstimateServiceSpec.groovy
package org.grails.guides

import grails.testing.gorm.DataTest
import grails.testing.services.ServiceUnitTest
import spock.lang.Specification

class ValueEstimateServiceSpec extends Specification implements ServiceUnitTest<ValueEstimateService>, DataTest {

    void setupSpec() { (1)
        mockDomain Make
        mockDomain Model
        mockDomain Vehicle
    }

    void testEstimateRetrieval() {
        given: 'a vehicle'
        def make = new Make(name: 'Test')
        def model = new Model(name: 'Test', make: make)
        def vehicle = new Vehicle(year: 2000, make: make, model: model, name: 'Test Vehicle')

        when: 'service is called'
        def estimate = service.getEstimate(vehicle)

        then: 'a non-zero result is returned'
        estimate > 0

        and: 'estimate is not too large'
        estimate < 1000000
    }
}
1 When mocking multiple objects using the updated testing framework in Grails 3.3 we now perform mocks during setup and no longer require the @Mock annotation.

We’ve kept things pretty simple in this test, since we don’t have very complex logic to test, but also so you can focus on the basic formula of the Spock test case. Spock provides a set of keywords which allow you to lay out your test in a very human-readable form.

  • given indicates a "setup" block - here you can set up any objects or variables needed to complete your test.

  • when and then are one of the most common "pairings" in Spock (another one, not used here, is expect/where - they define a statement and an expected result.

  • and simply continues on the current then block, but it allows you to specify your expectations for multiple assertions. Note that all of these blocks accept (optionally) a string description, which makes your test even more readable. E.g., when: "this method is called", then: "expect this result".

Go ahead and rerun this test - if all’s well, it should pass with flying colors.

$ ./grailsw test-app org.grails.guides.ValueEstimateServiceSpec

...

BUILD SUCCESSFUL

| Tests PASSED

10 Deploying your App

The final step in developing a Grails application is building the finished project into a deployable package. Typically Java web applications are deployed as WAR files, and Grails makes this easy with the war command:

$ ./grailsw war
...
BUILD SUCCESSFUL

| Built application to build/libs using environment: production

We didn’t cover the topic of configuration in this guide (although we did make some edits to our config files), but it’s worth mentioning here that Grails supports to concept of Environments, such as "development", "test", and "production". Each environment can have its own config properties and values, so you can have different settings between your development and production systems. By default, the war command uses the "production" environment - you can override this using the -Dgrails.env flag, like so:

$ ./grailsw war -Dgrails.env=development
...
BUILD SUCCESSFUL

| Built application to build/libs using environment: development

Once we have our WAR file, we can deploy it in any JEE container, such as Tomcat.

Congratulations! You’ve built your first Grails application.

11 Do you need help with Grails?

Object Computing, Inc. (OCI) sponsored the creation of this Guide. A variety of consulting and support services are available.

OCI is Home to Grails

Meet the Team