## 6.1.3 Models and Views

#### Returning the Model

A model is essentially a map that the view uses when rendering. The keys within that map translate to variable names accessible by the view. There are a couple of ways to return a model, the first way is to explicitly return a map instance:

    def show = {
        [ book : Book.get( params.id ) ]
    }

If no explicit model is returned the controller's properties will be used as the model thus allowing you to write code like this:

    class BookController {
        List books
        List authors
        def list = {
            books = Book.list()
            authors = Author.list()
        }
    }

> This is possible due to the fact that controllers are prototype scoped. In other words a new controller is created for each request. Otherwise code such as the above would not be thread safe.

In the above example the `books` and `authors` properties will be available in the view.

A more advanced approach is to return an instance of the Spring ModelAndView class:

    import org.springframework.web.servlet.ModelAndViewdef index = {
        def favoriteBooks = … // get some books just for the index page, perhaps your favorites    // forward to the list view to show them
        return new ModelAndView("/book/list", [ bookList : favoriteBooks ])
    }

#### Selecting the View

In both of the previous two examples there was no code that specified which view to render. So how does Grails know which view to pick? The answer lies in the conventions. For the action:

    class BookController {
        def show = {
             [ book : Book.get( params.id ) ]
        }
    }

Grails will automatically look for a view at the location `grails-app/views/book/show.gsp` (actually Grails will try to look for a JSP first, as Grails can equally be used with JSP).

If you wish to render another view, then the render method there to help:

    def show = {
        def map = [ book : Book.get( params.id ) ]
        render(view:"display", model:map)
    }

In this case Grails will attempt to render a view at the location `grails-app/views/book/display.gsp`. Notice that Grails automatically qualifies the view location with the `book` folder of the `grails-app/views` directory. This is convenient, but if you have some shared views you need to access instead use:

    def show = {
        def map = [ book : Book.get( params.id ) ]
        render(view:"/shared/display", model:map)
    }

In this case Grails will attempt to render a view at the location `grails-app/views/shared/display.gsp`.

#### Rendering a Response

Sometimes its easier (typically with Ajax applications) to render snippets of text or code to the response directly from the controller. For this, the highly flexible `render` method can be used:

    render "Hello World!"

The above code writes the text "Hello World!" to the response, other examples include:

    // write some markup
    render {
       for(b in books) {
          div(id:b.id, b.title)
       }
    }
    // render a specific view
    render(view:'show')
    // render a template for each item in a collection
    render(template:'book_template', collection:Book.list())
    // render some text with encoding and content type
    render(text:"<xml>some xml</xml>",contentType:"text/xml",encoding:"UTF-8")

If you plan on using Groovy's MarkupBuilder to generate html for use with the render method becareful of naming clashes between html elements and Grails tags. e.g.

    def login = {
        StringWriter w = new StringWriter()
        def builder = new groovy.xml.MarkupBuilder(w)
        builder.html{
            head{
                title 'Log in'
            }
            body{
                h1 'Hello'
                form{
                }
            }
        }    def html = w.toString()
        render html
    }

Will actually call the form tag (which will return some text that will be ignored by the MarkupBuilder). To correctly output a <form> elemement, use the following:

    def login = {
        // …
        body{
            h1 'Hello'
            builder.form{
            }
        }
        // …
    }