Scaffolding

Scaffolding

What is Scaffolding?

Scaffolding allows you to auto-generate a whole application for a given domain class including:

  • The necessary views
  • Controller actions for create/read/update/delete (CRUD) operations

Enabling Scaffolding

The simplest way to get started with scaffolding is to enable scaffolding via the "scaffold" property. For the "Book" domain class, you need to set the "scaffold" property on a controller to true:

class BookController {
   def scaffold = true
}

The above works because the "BookController" follows the same naming convention as the "Book" domain class, if we wanted to scaffold a specific domain class you can reference the class directly in the scaffold property:

def scaffold = Author

And thats it! If you run this grails application the necessary actions and views will be auto-generated at runtime. The following actions are dynamically implemented by default by the runtime scaffolding mechanism:

  • list
  • show
  • edit
  • delete
  • create
  • save
  • update

An interface like the one demonstrated in the screenshots below will be generated automatically:

If you prefer to keep your domain model in Java and mapped with Hibernate you can still use scaffolding, simply import the necessary class and set the scaffold property to it.

Dynamic Scaffolding

Because Grails does not use code templates to achieve this you can add your own actions to the scaffolded controller that interact with the scaffolded actions. For example, in the below example, changeAuthor redirects to the show action:

class BookController {
   def scaffold = Book

   def changeAuthor = {
        def b = Book.get( params["id"] )
        b.author = Author.get( params["author.id"] )
        b.save()

        // redirect to a scaffolded action
        redirect(action:show)
   }
}

You can also override the scaffolded actions with your own actions if necessary:

class BookController {
   def scaffold = Book

   // overrides scaffolded action to return both authors and books
   def list = {
         [ "books" : Book.list(), "authors": Author.list() ]
   }
}

Overriding Default Scaffolding

If you decide you don't like the default look and feel of the scaffolding, or want modify the default behavior of the scaffold code, you have the option of installing the scaffolding to your project, then tweak it there. To install the scaffolding code to your project type:

grails install-templates

and the template scaffold code will then be installed in the src/templates directory of your project. You can then edit the code templates to your liking and have the changes occur across the board. This is a really good way to customize your look and feel across the board. This is also discussed in Artifact and Scaffolding Templates.

Generating Static Controllers & Views

The above scaffolding features are useful but in real world situations its likely that you will want to customize the logic and views. Grails allows you to generate a controller and the views used to create the above interface via the command line. To generate a controller type:

grails generate-controller

Or to generate the views type:

grails generate-views

Or to generate everything type:

grails generate-all

All these commands will prompt you for the name of the domain class to generate to various artifacts for the specified domain class. You can even generate a controller and views for a domain class that is written in Java and mapped with Hibernate!

Customising the Generated views

The views that Grails generates have some form of intelligence in that they adapt to the Validation constraints. For example you can change the order that fields appear in the views simply by re-ordering the constraints in the builder:

def constraints = {
      title()
      releaseDate()
}

You can also get the generator to generate lists instead of text inputs if you use the "inList" constraint:

def constraints = {
      title()
      category(inList:["Fiction", "Non-fiction", "Biography"])
      releaseDate()
}

Or if you use the range constraint on a number:

def constraints = {
        age(range:18..65)
}

Restricting the length via a constraint also effects how many characters can be entered in the generated view:

def constraints = {
        name(length:0..30)
}

And you can change an input field to be a text area by using the "widget" constraint:

def constraints = {
        description(widget:'textarea')
}

Java Integration

If your domain model is written in Java and mapped with Hibernate you can still take advantage of Grails' scaffolding mechanism. For the purpose of this documentation it is assumed you have read how Grails' Hibernate integration works in the section on GORM, needless to say to scaffold a hibernate domain class simply reference the domain class in the controller:

import com.books.HibernateBook
class BookController {
     def scaffold = HibernateBook
}

If you want to generate the controller and views for a Hibernate domain class you can still do so, but make sure you type the full package and class name.

To integrate with the Grails constraints mechanism and hence hook into useful things like the way the views are generated and Grails' Validation mechanism you can do so by creating a Groovy script following the naming convention of your domain class and ending in the "Constraints" suffix. For example for the "HibernateBook" class defined above you would need to create a "com/books/HibernateBookConstraints.groovy" script in the same package is the class itself. Within the script just define constraints in the same way as you would do in a GORM class but without the def or static keywords before the name:

com/books/HibernateBookConstraints.groovy
constraints = {
      title(length:5..15)
      desc(blank:false)
}

Labels

 
(None)
  1. Sep 01, 2006

    graeme says:

    Please do not embed other languages into the user guide, if you want translation...

    Please do not embed other languages into the user guide, if you want translations please create a new page like Korean Scaffolding

  2. Mar 07, 2007

    Alex Wei says:

    I'm trying out the Bookmark sample in the book. How can I prevent 'dateCreated' ...

    I'm trying out the Bookmark sample in the book. How can I prevent 'dateCreated' from being input by user?

  3. Dec 26, 2007

    nurul choudhury says:

    I love the entire scaffolding concept. As intended, it give a rapid jump up by g...

    I love the entire scaffolding concept. As intended, it give a rapid jump up by giving a starting point for an application. But I would like to see more. At the moment the scaffolding is giving a nieve implemenattion of CRUD operations in the domain object. This is my opinion is too little. The doamin model is powerful enough to give a great deal on control over the relationships in the domain model, and this is a good thing. But it is not enough.

    It is my opinion that allowing a few more relationship use-cases Grails would have the ability not simply to provide a list of CRUD operation on the domain, but it could do 80% of most typical business applications. Besides the ability to create the operations it there was a declaritive ability to add 'maker/checker' workflow declaratively; Grails would find a nice home in may business applications.

    I write this comment because I am starting to put my thoughts on paper on how this might work in Grails. on how this might work in Grails. I am doing a simple prototype by updating the generator scripts to experiment with this capability. I will be publishing my suggestions shortly.

    I am sure that the initial implementation will be a throw-away sine I have not studied the Grails infrastructure carefully enough, nor do I have the Grains design knowledge to do this work in the correct way. My intension is not to put too much effort into the first prototype but just to understand how this will work.