Chapter 5. Controlling application flow


This chapter covers

  • How controllers, models, and views interact
  • Implementing custom URLs and permalinks
  • Writing filter code to reroute requests
  • Using services for more maintainable architecture
  • Data binding and error handling
  • Using Command objects for tricky form validations
  • Uploading and rendering images

In chapters 3 and 4, we spent plenty of time looking at how Grails handles domain objects. Along the way, we’ve used controllers and implemented a few GSP views to host our forms, but we’ve largely ignored how controllers work. It’s time to set that right.

In this chapter, we’ll focus on controllers. We’ll learn more advanced binding techniques for passing variables between forms and controllers, get some insight into how redirects work, implement file uploads, open the lid on filters, and even render custom content types. Along the way, we’ll beef up Hubbub to handle uploading and display profile photos, and we’ll implement the core business of creating Users and Posts. By the end of the chapter, you’ll be ready to implement the common controller use cases in your own applications, and quite a few of the edge cases.

We’ll get the chapter underway by pulling together all you’ve learned so far about controllers, forms, and domain classes. We’ll modify Hubbub to add and display user posts on a Twitter-style timeline.

5.1. Controller essentials

In our exploration of the Grails ecosystem so far, we’ve been more focused on the model (saving and querying domain objects) and passed over the gritty details of how controllers, views, and taglibs work together. Let’s take a more detailed look at form-controller interactions with a focus on the controllers.

Imagine that we want to display a timeline of a user’s recent posts. We’d need to implement a controller action (perhaps timeline in the Post controller) to retrieve the posts for a user, then pass them to a view (/views/post/timeline.gsp) to display them in the browser. As we discovered in chapter 1, Grails exposes controller actions as URLs using conventions. Here’s how Grails translates controller action names into URLs :

When the user points their browser at http://localhost:8080/hubbub/post/timeline/chuck_norris, for example, Grails will fire the timeline action on the Post controller, passing chuck_norris as the id. Typically, that action will retrieve some data from the database and pass it to the view to display. Under Grails conventions, the view name matches the action name (but with a .gsp extension), so the timeline action will retrieve the data and pass it to /views/post/timeline.gsp to be rendered. Figure 5.1 demonstrates this flow.

Figure 5.1. From URL to controller to view

You saw this flow in action in chapter 1 and in the search form examples in chapter 4. Let’s apply our knowledge of controllers to add a timeline to Hubbub.

5.1.1. Implementing a timeline for Hubbub

A timeline for a user should display a list of posts for the user mixed with posts by everyone they follow. But let’s start small and implement the capability to display all the posts for one user.

We’ll start by updating our PostController to implement a timeline() action. Listing 5.1 shows our first implementation of a user timeline:

Listing 5.1. Adding the timeline action to our PostController

As you’ve seen in earlier chapters, actions typically process form parameters and use them to interact with the data model. In this case, we’re using the optional id parameter to hold the user’s ID, and we use it to retrieve the entire User object from the database . In a production application, you’d probably want to do some null checking there. We’ll add some error handling later in the chapter.

Once you’ve retrieved the User object, the result of the action then gets placed into a map that is returned to the view , which is typically a GSP file. The view can access any objects in the map to display them to the user. We could use an explicit return statement at the end of our action, but there’s no need. Groovy always considers the last line of a closure or method as the return value, and it’s common for Grails programmers to omit return in controller actions.


The optional id param

You may not have seen the id field in action yet. As illustrated at the beginning of section 5.1, the conventional URL-to-controller mapping is /controller/action/id, where the id portion is passed into the params.id field. Because the format of the field is free-form, it gives you some cool options for permalinks.

For example, /user/profile/chuck_norris would fire the profile() action on the User controller, passing in chuck_norris to the params.id. This was how people commonly did permalinking before Grails implemented custom URL mappings, which we’ll get to in section 5.7 of this chapter.

Grails scaffolds use the id field to represent the database ID, so you’ll often see URLs like /user/show/57 being used to display the user with id 57 from the database. It’s practical, but it sure ain’t pretty.


We can now retrieve the user from the database, so it makes sense to implement a view to display the information. Following Grails conventions, we’ll implement our view in a file that has the same name as our controller and action. In this case, the view will be named /grails-app/views/post/timeline.gsp. Listing 5.2 shows our first effort at displaying the user’s timeline.

Listing 5.2. Displaying a user’s timeline

By making use of the User object that the controller placed into our request scope (which we’ll discuss in section 5.1.3), we’re able to read the User’s fields and display the data in the browser. In this example, we access the User’s Profile object, and display the full name .

We can reference objects in request scope by enclosing their name in Groovy’s interpolation syntax, ${}. If you pass complex objects to your view (for example, a domain object with relationships to other domain objects), you can access them as you would in any other setting. In listing 5.2, we render ${user.profile.fullName} .

We also iterate over each of the User’s Post objects , displaying the content and dateCreated of each post .

Figure 5.2 shows our new timeline view in action. With the timeline in place to show all the user’s posts, we can now work on adding new posts to the timeline. This will give us a good chance to create and save domain objects.

Figure 5.2. Our first timeline in action


Breaking view name conventions

If you don’t want your view name to match your action name, you can use the render() method. For instance, if you want to use user_timeline.gsp to generate the output for your timeline action, you can use the view argument to render():

render(view: "user_timeline", model: [ user: user ])

Notice that you omit the .gsp extension when referring to the view.


5.1.2. Adding new posts

In chapter 3, we learned how to create and save Post objects from a unit test. Now that we know a little about how controllers work, let’s apply our knowledge to the UI.

First, let’s enhance our view to give our user the ability to add new posts. We want to end up with the sort of capability shown in figure 5.3.

Figure 5.3. Adding posting capabilities to Hubbub

For this to work, we need to add a form to timeline.gsp to capture the new content for the post. We’ll need a textArea component so the user can enter the body of the post. Listing 5.3 shows the div we’ll add to our timeline.gsp file to handle the new input.

Listing 5.3. Adding a form for new posts

In listing 5.3 we’ve added a new form to the page using the <g:form> tag, with the target of the form being the addPost action . We pass through the current id field to the form submission, so the addPost action knows which user ID it’s being invoked for. For example, the form submission URL for the “chuck_norris” user ID would be /post /addPost/chuck_norris.

We’ve also added the <g:textArea> tag to let the user enter their post contents . Because the control is named content, we can expect params.content to turn up in our controller logic somewhere.

Listing 5.4 shows our updated PostController code, which now handles adding new posts to the user’s timeline.

Listing 5.4. The updated PostController handles new Post objects

When we were saving domain models in chapter 3, we wrote integration tests. Now we’re doing it for real from the UI. Like our timeline action, addPost starts by retrieving the User object based on its ID , but here we’ve added some basic error handling to test whether the user exists.

If the User exists in the database, we create a new Post object, passing in the params map . As you learned in chapter 2, when you pass a map into a constructor, Groovy binds the properties of the map to fields on the object, skipping the ones that don’t match. In this case, params.content will be mapped to the Post’s content field. Figure 5.4 shows how the content field of the params object maps to the Post object. Grails refers to this process as data binding.

Figure 5.4. Binding a params map to a Post object

With the form data bound to our new Post object, the new Post is added to the User object . Finally, we can attempt a save() to ensure that constraints on the Post object are satisfied .

Whether things go well or fail dismally, we keep the user informed by providing feedback with flash.message . We’ll discuss flash scope in the next section, but in short it’s a way to communicate information to the user. Later in the chapter, we’ll show you a more robust way of handling validation errors, but flash.message will be fine for now.

When everything is done, we redirect the user back to the timeline action which will rerender the timeline with the new post. Notice that the redirect includes the id param. This is important, because the timeline action relies on having the user’s ID, and when we redirect programmatically (rather than typing in a browser URL), we need to explicitly provide the value.

We now need to update our timeline.gsp file to output those error or success messages to the user. The following code fragment shows the updated div for our flash message:

<g:if test="${flash.message}">
<div class="flash">
${flash.message}
</div>
</g:if>

We’ll need to style the div with CSS so that it stands out as a warning message. If you download the source for the chapter you’ll find the necessary CSS styling to match the screen shots that follow.

With our basic error handling in place, it’s time to experiment with adding an invalid post. Figure 5.5 shows the result of attempting to add a blank post. Our validation is firing and we’ve implemented the capability to add new posts to Hubbub.

Figure 5.5. Adding a blank post generates an error.

You’ve now implemented a basic version of two of Hubbub’s major features: displaying the user’s timeline, and adding posts. You’ve also applied your knowledge of creating domain objects (from chapter 3) and using dynamic finders to query them (from chapter 4).

But there are still a few things unexplained. Where did all these flash objects come from, and what do they do? And why aren’t we using the standard validation messages we saw in chapter 4? Fear not. By the end of the chapter, you’ll understand all these essential controller issues.

We’ll start with the flash object, which relates to how Grails handles scope.

5.1.3. Exploring scopes

You’ve seen how controller actions can return a map that gets passed through to the view, and you’ve seen the flash object also passing data from controller to view. This passing of information, and the lifetime of the variables that you pass, is known as variable scope.

Grails supports different scopes to store information in, and each of them lasts a different length of time. When you passed data in a map from a controller to a view, you were implicitly making use of request scope. But Grails lets you reference the different scopes explicitly so you can store data for as long as you need it. In particular, Grails offers you four special map-like storage scopes that you can reference by name in every controller action. They are listed in table 5.1.

Table 5.1. Grails supports four storage contexts for passing content between controllers and forms

Scope variable

Survival time for entries in this scope

request

Survive until the target GSP finishes rendering

flash

Survive to the next page, and the one after that

session

Survive until the current user closes the browser

servletContext

Survive until the application is restarted (this map is shared by all users)


Note

request, flash, session, and servletContext aren’t really Java Maps. For example, request is a Java HttpServletRequest object. But the underlying objects have been enhanced via some advanced Grails Meta-Class operations to expose map-like storage, making things much easier for the programmer.


If you’ve done work with Java web applications before, you’ve probably seen request, session, and servletContext scopes. Flash scope is unique to Grails, and it’s a real life saver. Figure 5.6 shows the relative lifespans of the different scopes. We’ll look at each scope individually, next.

Figure 5.6. Request scope is the shortest lived, and servletContext the longest.

Request Scope

Request scope is great when you want to store data that is shared only between your controller and the view (normally a GSP page). In this case, the server is said to “forward” the request to the page (meaning that the browser location doesn’t change—it’s all handled within the server itself). Even though you weren’t aware of it, we’ve been using request scope every time we returned a Map from our controller actions. Request scope is used to hold that data until the view has finished rendering it.

But what about our addPost() action? We do the heavy lifting of adding a post, but then we want to redirect the browser to the user’s timeline to display a “Successfully added” message. That means the browser is involved, which means our request scope is gone.

For these scenarios, Grails offers flash scope.

Flash Scope

Entries in the flash map survive one (and only one) redirect, after which they’re removed. That’s exactly what we need for our addPost() action. We can safely place a “Successfully added” message into our flash map and know that it will survive the redirect back to our timeline action.

Like all of these scope maps, flash is a general purpose map, but convention dictates that you put these kind of UI messages in an attribute called flash.message. You’ll commonly see flash scope referenced in GSP files wrapped in a conditional to keep things tidy, as in our earlier Post example. Here’s a sample of the kind of code you’ll commonly encounter in a GSP:

<g:if test="${flash.message}">
<div class="flash">${flash.message}</div>
</g:if>

For objects that you want to survive longer than a single redirect, you’ll need to explore session scope.

Session Scope

The next longest lived scope is session scope. Objects that you place in session scope remain until the user closes their browser. Internally, servers use a session cookie called JSESSIONID to map a user to their session, and the cookie expires when they close their browser (or when the server times out the session due to inactivity).

Sessions are replicated in a clustered environment, so it’s best to keep their contents to a minimum. A common use case is putting a logged-in User object into the session, so be sure you understand how detached domain objects work (see the sidebar).


Session gotchas: the mystery of the detached object

If you’re storing a domain object in the session (such as the logged-in User object), the object will become detached from your Hibernate session. That means you won’t be able to access any uninitialized lazy-loaded relationships the object holds. For example, you won’t be able to call session.user.following.each {}. To reattach the object (so you can walk its object graph of relationships, for instance), use the attach() method that is available on all domain classes. For our User example, it would look like this:

def user = session.user
if (!user.isAttached()) {
user.attach()
}
user.following.each { nextFollowing -> /* do stuff */ }

ServletContext (Application) Scope

The final scope available is servletContext scope, sometimes called application scope. This map is shared across your whole application, and it’s handy for storing state that’s not dependent on any particular user (such as the number of logins since the application was started). This scope is also useful for loading resources from within your web application itself (for example, servletContext.getResourceAsStream("/images/mylogo.gif")). Consult the standard servletContext Javadoc for details.


Note

There are also flow and conversation scopes, but we won’t cover those until chapter 9, which deals with Grails webflows.


We now have a good handle on how scopes work, and we’ve explained the mystery of that flash object. We store data in request scope for rendering in the view, in flash scope for surviving a redirect, in session scope for long-lived user-specific data, and in application scope for long-lived application-specific data.

It’s time to explore how controllers can talk to other controllers to route the user around the application. When we introduced our addPost() action, we called redirect() methods, so it’s time to learn about controller redirects and flows.

5.1.4. Handling default actions

Grails lets you supply a default index() action for each controller that you implement. When the user accesses the controller without specifying an action name (such as when accessing /hubbub/post), the index() action will handle the request (typically redirecting the user to some other action).

Let’s retrofit an index() action to our PostController, so that when the user navigates to /hubbub/post, they’re immediately redirected to the timeline() action of our scaffold. Listing 5.5 shows the updated PostController code.

Listing 5.5. Catching the index() action and redirecting the user

One of the gotchas when redirecting is that you lose your params map if you don’t explicitly pass it through to your redirected action. If we hadn’t passed params from the index() action, then had the timeline() action made use of any incoming param values, they would have been null.


A world of default-action alternatives

We’ve discussed using the index() action to perform default actions when hitting the base controller URL. But there are many ways to handle default actions.

For example, if your controller has only one action on it, that will be interpreted as the default action. In listing 5.5, if timeline() were the only action in the controller, we could have omitted the index() action and the controller would have handled requests for /hubbub/post.

If you have multiple actions in your controller, you can explicitly declare your default action at the top of your controller:

def defaultAction = 'timeline'

Using an index() action is very common, so we showed you that technique first. But in most of these sorts of scenarios, using defaultAction makes a lot more sense, because you don’t have to repackage your params and there’s no client redirect involved.


The typical role of an index() action is redirecting, but we haven’t explained the options for handling redirects. It’s time to get acquainted with the many redirect options.

5.1.5. Working with redirects

We’ve used redirect() calls throughout our code. For example, after we call addPost(), we redirect back to the timeline. When a default index() action is called, we redirect to another one.

All of our redirect() uses so far have followed a particular pattern, like this:

redirect(action:'timeline')

For this form of redirect, the target action name must exist on the current controller.

But what if you want to refer to an action on a different controller? Perhaps after registering a user on the User controller, you want to send them to the timeline on the Post controller. For those situations, you can use the extended version of redirect():

redirect(controller: 'post', action:'timeline', id: newUser.userId)

The id field is optional, as is the action name. If you don’t specify an action, it will go to the default action on the controller (as discussed in the previous section).

If you need to pass parameters during the redirect, you can pass in a map of parameters to be sent:

redirect(controller: 'post', action:'timeline',
params: [fullName: newUser.profile.fullName,
email: newUser.profile.email ]
)

Finally, you can also redirect using the uri: or url: params to redirect to relative or absolute addresses. For example, instead of this,

redirect(controller: 'post', action:'timeline')

you can use the URI option:

redirect(uri: '/post/timeline')

And if you need to go to an external address, use the URL version:

redirect(url: 'http://www.google.com?q=hubbub')

That’s about all you need to know about redirects. We’ll be using them a lot, so it’s good to be familiar with their many flavors.

Our next step is to take what we’ve implemented in this chapter, and move it to a more maintainable application architecture. One of the most powerful tools Grails offers for doing that is the Grails service.

5.2. Services: making things robust and maintainable

We’ve learned a lot of powerful techniques so far in this chapter: all sorts of data binding, controller routing, and redirect magic. But before things get unmaintainable, we’d better learn some techniques to keep a clean application for the long haul. In this section, we’ll explore how services can dramatically simplify your controllers.

So far in our PostController, we’ve implemented an addPost() action to handle the creation of new Posts. But later we’ll want to create Posts from many different entry points (specifically from a REST service and a Jabber gateway). That means our Post logic will need to be repeated in all those places. And because we’re DRY (Don’t Repeat Yourself) people, that repetition sounds like a bad thing.

In this section, we’ll extract all of our new-post functionality into a Grails service that we can call from anywhere we like. It will make things a whole lot tidier and more maintainable.

5.2.1. Implementing a PostService

It’s time to abstract our Post operations into a PostService that we can access from anywhere in our application. We first saw services in chapter 1, where we wrote a simple quote service to abstract the lookup process for quote generation. Services offer a simple, maintainable, and testable way of encapsulating reusable business logic. Services can participate in transactions, can be injected almost anywhere in your application, and are easy to develop.

Let’s create a PostService for Hubbub. It won’t surprise you that the process starts on the command line:

grails create-service com.grailsinaction.post

This will create a starter PostService.groovy file in /grails-app/services/com/grailsinaction.

In listing 5.6, we add some logic to our service so that we can add posts by supplying the userId and content of the post.

Listing 5.6. PostService.groovy defines PostService and a related exception class

In listing 5.6, we first define a new Exception, PostException, to handle any errors that we encounter with the save . We’ll use this exception to store an error message and any Post objects that fail validation. Groovy lets you define more than one class in a .groovy file, so we do that here to keep the exception with the service.

Next, we define our service, which, following Grails conventions, always ends in the name “Service” , and we mark it transactional . (We’ll explore transactional semantics in depth in chapter 14.) Our createPost() method takes a userId and the post’s content and returns a Post object or throws a PostException if things go bad.


Note

Because PostException extends RuntimeException in listing 5.6, Grails will automatically roll back any database transactions that happen inside the method. You’ll learn more about how this works in chapter 14.


This is a transactional service, so we can attempt the save() , which will return null if there are any validation errors, triggering our invalid-post exception . With the exception, we pass back the Post object itself, because clients might want to inspect and display the exact validation errors. If the save() goes well, we return the persisted Post object.

5.2.2. Wiring our PostService to our PostController

With our PostService in place, we now need to wire it up to the PostController. As you saw in chapter 1, this injection happens by declaring a property in the controller with the same name as the service (but with a lowercase first letter).

Listing 5.7 shows the updated PostController code, which now does all posting through the PostService.

Listing 5.7. An updated PostController that uses our new PostService

In listing 5.7, our controller has been updated to inject the PostService automatically . With our service in place, all we have to do is invoke the createPost() method and deal with any fallout from invalid posts .

Creating the PostService involved quite a bit of refactoring, but the result is a tidy, reusable service that we can use in later chapters for posting from REST services and message queues, so it was worth the effort.

There’s still lots to explore about services (such as whether they’re injected as singletons or prototypes, how transactions are preserved, and how to test them), and we’ll come back to them in chapter 14. We gave you a taste of services here because controllers are the most common place to use them, and this means we can take advantage of them later in the chapter.


Logging: a special case of injection

One special case of injection is the Grails logger. We haven’t used it yet, but every controller, service, and domain class is automatically injected with a Log4j log object (which happens through some MetaClass magic in the Grails bootstrap process rather than through classic Spring injection, but the result is the same).

You can use a log object wherever it makes sense:

log.debug "The value of user is: ${user}"

The log object can be particularly useful in exception scenarios. If you pass the exception as the second parameter to the log method, you get a full stack trace in your logs:

try {
user.punchChuckNorris()
} catch (e) {
log.error "Failed to punch Chuck Norris", e
}

Logging configuration is controlled by entries in your /grails-app/conf/Config.groovy file. You can even use the runtimeLogging plugin to change log levels while your application is running.


With our posting functionality now tidily abstracted in its own service, it’s time to explore other aspects of our controller that we can implement in more satisfying and maintainable ways.

The next vital area of controller operation that we need to be familiar with is data binding—how form data is parsed and validated and ends up in the database. We’ve used simple techniques so far, but it’s time to introduce you to a range of more powerful features.

5.3. Data binding

Now that you understand how services work, it’s time to revisit the way we get form parameters into domain objects. So far we’ve either manipulated data in the params map or bound incoming parameters with a new Post(params) style constructor, but what about cases where you don’t want to bind all parameters? Perhaps you don’t want the user to be able to supply their own /user/update?password=secret&userId=admin style overrides.

The process of marshaling parameters into object properties is known as data binding. We haven’t given you many approaches to this topic, so it’s time to delve a little deeper.

5.3.1. Binding to an existing object

Most of our data-binding explorations have focused on creating new domain objects from an incoming params object. But the update scenario is another common case—perhaps you’re letting the user change their profile with an updated email address.

Let’s say our user update action performs an update like the one in listing 5.8.

Listing 5.8. Data binding with properties can be perilous

In this example, we reattach a User object that we stored in session scope during login to the current thread’s Hibernate session. We then bind the params object to the user’s properties , so any parameter that matches the name of a user property will be updated on the User object. Finally, we validate the object to make sure all our constraints still hold , and we roll things back if they fail .

This updates the User properties as we intended. Notice the explicit discard() if validation fails . In Grails 1.0, if you didn’t explicitly discard() an object that failed validation, GORM would still persist it back to the database with the bad value. Under Grails 1.1, the explicit discard() is no longer required—Grails itself will mark any object failing validation as read-only, and it will never be persisted back to the database. If you’re switching between Grails 1.0 and 1.1, this is an important gotcha.

We now have a strategy for updating existing domain classes, but we haven’t looked at how we can exclude or include specific parameters in the binding. For that, we need to introduce you to bindData().

5.3.2. Whitelist and blacklist bind params

The bindData() method available in controllers lets you blacklist certain parameters from the marshalling process.

The two-argument version of bindData() is equivalent to a standard property assignment:

bindData(user, params)

This has the same result as the more-familiar assignment style of data binding that you’ve already seen:

user.properties = params

But bindData()’s blacklisting power is introduced when using the three-argument version of the command, which takes a list of properties to exclude from the binding process. If we wanted to exclude our userId and password parameters from the update, we could do something like this:

bindData(user, params, ['userId', 'password'])

That solves half the problem—the blacklisting of certain properties. What if we want to specify certain parameters to be included in the bind? Since Grails 1.1, the properties object supports a subscript operator that you can use in whitelist binding scenarios.

For example, if we only let the user update their email and fullName values, we can do things like this:

user.profile.properties['email', 'fullName'] = params

This will only update the email and fullName properties on the user’s Profile object, discarding all other parameters that match User property names.

Now that we’ve explored data binding for single domain classes, let’s explore how we can perform data binding on entire graphs of objects.

5.3.3. Complex forms: binding multiple objects

All of our examples so far have concentrated on binding a single domain class, but Grails also gives you the option of handling form submissions for nested objects. Consider user registration, for example. We need a User object (to handle the userId and password), and a Profile object (to handle the fullName, bio, homepage, email, and other attributes).

In listing 5.9, we implement a form that references fields on a User object and its Profile in a null-safe way. Submitting a form like this will allow you to create both the User and attached Profile in a single save.

Listing 5.9. A form that will update multiple domain objects in a single submit
<html>
<head>
<title>Register New User</title>
<meta name="layout" content="main"/>
</head>
<body>

<h1>Register New User</h1>

<g:hasErrors>
<div class="errors">
<g:renderErrors bean="${user}" as="list" />
</div>
</g:hasErrors>

<g:form action="register">
<dl>
<dt>User Id</dt>
<dd><g:textField name="userId"
value="${user?.userId}"/></dd>
<dt>Password</dt>
<dd><g:passwordField name="password"
value="${user?.password}"/></dd>
<dt>Full Name</dt>
<dd><g:textField name="profile.fullName"
value="${user?.profile?.fullName}"/></dd>
<dt>Bio</dt>
<dd><g:textArea name="profile.bio"
value="${user?.profile?.bio}"/></dd>
<dt>Email</dt>
<dd><g:textField name="profile.email"
value="${user?.profile?.email}"/></dd>
<dt><g:submitButton name="register" value="Register"/></dt>
</dl>

</g:form>

</body>
</html>

The registration form in listing 5.9 contains a number of fields from both the User and Profile objects. Notice that the profile-related fields are kept in form controls with the prefix “profile”: profile.fullName, profile.bio, profile.email. Grails makes use of this prefix when the form is submitted to bind the field to a relation on the saved object. Figure 5.7 demonstrates how the single set of parameters are split off into the User object and its nested Profile object.

Figure 5.7. Parameters are split into bound objects based on their prefix.

Listing 5.10 shows the new register() action, which we’ve added to the User-Controller. Creating and saving a User object based on the incoming params object binds all those Profile fields as well.

Listing 5.10. Implementing a register() action for the UserController
def register = {

def user = new User(params)
if (user.validate()) {
user.save()
flash.message = "Successfully Created User"
redirect(uri: '/')
} else {
flash.message = "Error Registering User"
return [ user: user ]
}
}
}

If user.validate() fails, we return to the registration form, passing the failing User object. If we have an object with validation errors, we use the <g:hasErrors> and <g:renderErrors> tags to display them. Recall the errors div in our registration form (listing 5.9):

<g:hasErrors>
<div class="errors">
<g:renderErrors bean="${user}" as="list" />
</div>
</g:hasErrors>

The <g:renderErrors> tag renders validation messages for the named bean as an HTML unordered list (<ul>), which is convenient for informing the user what’s wrong. This is the same mechanism scaffolds use to display validation errors (which you saw in chapter 4). Figure 5.8 shows our new registration form in action, rendering appropriate error messages.

Figure 5.8. You can bind multiple domain objects on a single form and include error handling.

We’ve now implemented a basic registration process, and even thrown in some error handling to keep it tidy. But you might be wondering how the error handling works behind the scenes. It’s important to get a handle on how errors work, in case your application needs custom layout and rendering of error messages for particular fields. Let’s take a look.

5.3.4. Error handling

In the previous section, we passed a User object that had failed validation through to the view. The view then made use of the <g:hasErrors> and <g:renderErrors> tags to display the error messages (as in figure 5.8). You might be curious how those tags know what the failing validations are.

In chapter 3 (section 3.3), we saw that calling user.validate() populates a user.errors object with failing validations. The hasErrors() and renderErrors() methods use this object to iterate through the errors.

But what if you want to highlight the individual field values that are failing validation, rather than listing them all at the top of the page? You can take advantage of a special version of the hasErrors tag that specifies a domain object in request scope as well as the field you’re rendering. Listing 5.11 shows an example of rendering the email validation errors next to the email field.

Listing 5.11. Implementing field-level errors is hard work at the moment.

In listing 5.11, we use the <g:hasErrors> tag to find any validation errors for the email field on the user’s Profile object . If any errors exist, we use the <g:each-Error> tag to iterate through them . Remember that a given field may fail more than one validation. Finally, we resolve the error message from our resource bundle by using the <g:message> tag .

After seeing all that, you probably feel that <g:renderErrors> is pretty nice after all. Hopefully a future version of Grails will make marking-up field-level errors much less painful.

Figure 5.9 gives you an idea of the kind of markup generated by the techniques in listing 5.11. As you can see, you can co-locate the errors, but it’s a lot of work, and a red asterisk next to the failing field is probably as effective.

Figure 5.9. Field-level markup of errors is difficult but achievable in Grails 1.1.

Now that you understand some of the power of Grails’ data binding, and you’ve learned how errors work, it’s time to introduce you to one last technique for data binding that makes the whole operation a lot more maintainable: Grails’ command objects.

5.4. Command objects

All of this data binding and manipulation is wonderful, but what happens when there isn’t a one-to-one mapping between the form data and a domain object? For example, a registration screen might have both “password” and “confirmPassword” fields that need to match to ensure the user hasn’t made a mistake entering the password.

For these sorts of scenarios, Grails offers the command object. The command object’s purpose is to marshal data from form parameters into a non-domain class that offers its own validation.

5.4.1. Handling custom user registration forms

User registration involves subtle validations that only make sense during the registration process (like the example of matching passwords). Let’s cook up a UserRegistrationCommand object to see how you might capture both sets of data in a single command object.

Typically, command objects are single-use objects, so by convention they’re created inside the same .groovy file as the controller that uses them. For our example, let’s enhance the UserController class with the new command class, as shown in listing 5.12.

Listing 5.12. A UserRegistrationCommand class

There’s quite a lot of validation going on there! We’ve incorporated all the validation from both our User and Profile objects, which won’t be new to you. We’ve also added a custom field and validation that’s specific to the registration process (specifically, that password and passwordRepeat must match).

Command objects are particularly useful in scenarios where you have different or augmented validation rules firing for the form submission that aren’t in your domain model. A password-confirmation field is a classic example.

The neatest part of the command object process is writing a controller action to consume the form submission. Reference the command as the first argument to the action closure, and the binding occurs automatically. Listing 5.13 shows our custom action register2() for handling our command object.


DRY strategies for reusing validators

You might be wondering if there is a more DRY (Don’t Repeat Yourself) way to reuse the constraints from domain classes in your command objects. There are no built-in mechanisms, but people have been creative in the way they approach the problem. There are three basic options. By using standard assignments between classes, you can share:

  • the constraints closure in its entirety
  • the map of constraints for a single field
  • custom validator closures

None of these solutions are elegant, and we look forward to seeing a better DRY validation mechanism in a future Grails release.


Listing 5.13. A register action that uses command objects

In listing 5.13, the command object is passed in as the first argument to the action’s closure , causing Grails to attempt to bind all incoming params entries to the command object’s fields. Validations are then applied, and we can check the results by calling hasErrors() on the command object itself .

If the data looks good, we can bind the command object’s fields to the various domain classes. In listing 5.13, we bind to both User and Profile and then attempt to save the new user.

We have to confirm that the save() is successful , because some constraints only make sense in a domain class, not in a command object. (For example, our User class has a unique constraint on the userId). Although you could attempt to simulate a unique constraint on your command object with a custom validator, even then the user isn’t guaranteed to be unique until the real save() is committed to the database.

Command objects are great for this sort of form, where you don’t have a one-to-one mapping with a domain class. But they also offer other features. Command objects can participate in injection, for example.

5.4.2. Participating in injection

Command objects aren’t dumb value objects with a little validation. They’re subject to the same bean-injection features as controllers, which means they can make fantastic encapsulators of business logic.

In our UserRegistrationCommand example, the user enters a clear-text password, but let’s imagine we wanted to store it encrypted in the database. If we had defined a cryptoService, we could inject it directly into the command object. We might do something like this:

class UserRegistrationCommand {

def cryptoService

String getEncryptedPassword() {
return cryptoService.getEncryptedPassword(password)
}

// our other properties and validators
}

We could then use the cryptoService to do the heavy lifting to ensure that there’s only one class that knows how password encryption is implemented. Adding a convenience routine like getEncryptedPassword() to our command class makes consuming the command class in our controller code a lot tidier.

Now that we’ve covered data binding and controller logic, all that’s left for this chapter is the sweet stuff. We’ll move on to handling photo uploads, creating a basic security file, and customizing the site’s URLs.

Let’s start by looking at how we’ll upload user profile photos.

5.5. Working with images

We’ve now seen nearly every controller trick that you’re likely to want to use in your next Grails project. There are, however, a few outliers—you won’t need them in every application, but when you need them, you really need them.

In this section, we’re going to explore how to handle file uploads (our user’s profile photo) and how to render custom content types (image data, in our case). Although your next application might not have much use for photos, the techniques are useful for whatever kind of content you want to render.

5.5.1. Handling file uploads

What’s a social-networking site without the ability to upload photos and avatars? But if you’ve ever added file-upload capabilities to a Java web application, you know the complexities involved (not only the mess involved when handling byte streams, but also handling security issues, such as limiting file sizes to prevent denial-of-service attacks). Grails puts that complexity behind you. Let’s set to work implementing a photo-upload capability for Hubbub.

We’ll start by creating an ImageController to handle image uploading and rendering:

grails create-controller com.grailsinaction.Image

There are two ways to handle file uploads in a controller, and which one you select depends on what you want to accomplish. If you want to store the image in a domain class, your best option is to use a command object. Listing 5.14 shows how to use a command object for photo uploads.

Listing 5.14. Handling image uploading via a command object

The upload process for images using a command object binds the uploaded image data to a byte array.

To actually be able to select a photo for upload in our browser window, we need a view with an Upload control. The form also needs to be tagged to tell the browser that the form contains a file upload, so we’ll use the <g:uploadForm> tag, as shown in listing 5.15.

Listing 5.15. An image-upload form
<g:uploadForm action="upload">
User Id:
<g:select name="userId" from="${userList}"
optionKey="userId" optionValue="userId" />
<p/>
Photo: <input name="photo" type="file" />
<g:submitButton name="upload" value="Upload"/>
</g:uploadForm>

Remember, the upload form needs to use <g:uploadForm> instead of <g:form>, and it needs an input box with type="file" to hold the image upload data.

The browser will render the form in listing 5.15 with an upload box as shown in figure 5.10.

Figure 5.10. Our image-upload form in action

With our command object backing the upload, users are only a click away from getting their profile pictures into the database.

5.5.2. Uploading to the filesystem

If you want to store the uploaded image in the filesystem rather than the database, you need access to the raw Spring MultipartHttpServletRequest object that backs the upload process.

For this case, you have more options for storing the byte array:

The MultipartHttpServletRequest class has a transferTo() method for moving the picture data directly to a file, which is convenient if you’re averse to storing BLOBs in your database. For a detailed discussion of MultipartHttpServletRequest, consult the Spring Javadoc.

5.5.3. Rendering photos from the database

Now that our photos can be uploaded to the database or filesystem, we need a way to display them. We’ll create <img> tags in our application and have Grails retrieve our profile photos and render them.

First, we’ll create a new profile view, so the UserController can view a profile, and we’ll include a link to the user’s profile picture. Let’s call the view /views/user/profile.gsp and give it an HTML image tag:

This code fragment creates a link back to /image/renderImage/id based on the userId of the current user. Once we’ve implemented our renderImage() action in ImageController, we can link our image tags to /image/renderImage/chuck_norris or any other user ID.

Listing 5.16 shows how we can send image data to the client.

Listing 5.16. Sending image data to the browser

As listing 5.16 shows, to write to the browser, you write the bytes directly to the response’s output stream, and you also need to tell the browser the size of the data.

With our backend rendering implemented, figure 5.11 shows the result for /user /profile/chuck_norris.

Figure 5.11. Rendering a profile picture

We now have a basic profile screen running, which completes our explorations of image rendering and all the UI functionality we’ll be doing in this chapter. We’ll learn a lot more UI techniques in chapter 6, but for now there are still two more important controller features to learn about: filters and URL mappings. Both affect how a user navigates your application, and an understanding of both is essential for developing powerful Grails applications.

Let’s start with exploring filters.

5.6. Intercepting requests with filters

So far in this chapter, we’ve spent a lot of time looking at the frontend user experience. But there are also important techniques that you need to implement at the backend. In this section we’ll explore the use of filters for augmenting the Grails request/response pipeline with your own custom processing.

5.6.1. Writing your first filter

Grails filters give you a powerful tool for intercepting every request (or a subset of requests) and for performing business logic before or after the controller action fires. If you’ve worked with Java Servlet filters, you might recognize Grails filters as providing similar functionality, although Grails filters only intercept controller requests, not static file requests for JavaScript, CSS, image files, and the like.

A classic example of where you might want this sort of approach is a security filter—you want to check that a user has access to a target resource (some popular Grails security plugins use Grails filters for this purpose). Let’s put a simple security filter together to show you how it can be done.

First we’ll create a shell for our filter:

grails create-filters LameSecurity

This command will write a starter template in /grails-app/conf/LameSecurityFilters.groovy (note the plural “Filters”; if you name it with the singular form, it won’t fire).

Next we’ll modify our filter to perform some simple checks, as shown in listing 5.17.

Listing 5.17. A basic security filter implementation

You can name the filters that you put into the file (for documentation purposes only), so it’s good to choose names that summarize your filter logic. In listing 5.17, we’ve chosen to call our set of rules secureActions .

You can put as many filters as you like in the file, and all matching rules will fire in order from the top until one returns false from its before() closure. As you’ll learn soon, you can apply filters to wildcards (controller: '*' action: '*'), but in listing 5.17, we only want the filter to fire for the addPost or deletePost actions . Using Boolean operators lets you fine-tune the application of the filter.

Inside the body of the filter, you can provide closures for before, after, or after-View. Table 5.2 outlines the filter lifecycle phases and their typical features.

Table 5.2. Lifecycle phases and their usage

Closure

Fires when?

Useful for

before

Before any controller logic is invoked

Security, referrer headers

after

After controller logic, but before the view is rendered

Altering a model before presentation to view

afterView

After the view has finished rendering

Performance metrics

Our before closure checks that the user provided a logonId parameter , and if so, and the corresponding user exists, it stores the User object in the session to signify a login. Otherwise it redirects to the login screen .

If any before closure returns false, as happens at , no other filters will fire and the controller action won’t be invoked. This is typically done when you have a filter (such as a security filter) that has redirected the request.

We’ve also added an afterView closure to demonstrate some diagnostic options, and to show you some of the variables that Grails provides in filters. Although filters don’t have all of the functionality of controllers, they expose the common controller variables that we covered earlier in the chapter (request, response, params, session, flash, and a few filter-specific extras). They also have two methods: redirect() and render(). Table 5.3 shows you some additional filter variables that we haven’t made use of.

Table 5.3. Variables exposed to filters

Variable

Description

controllerName

Name of the currently firing controller

actionName

Name of the currently firing action

applicationContext

The Spring application context—useful for looking up Spring beans, but filters support dependency injection, which is much cleaner

grailsApplication

The current grailsApplication object—useful for finding out runtime information, such as the Grails version or application name

Although we haven’t made use of it in listing 5.17, there’s also a special case for the after closure that takes a model as an argument. That’s the model map that the controller returns from the action that handled the request. You can augment that model in your filter, and modify it if you must.


Tip

Modifying existing model values in your filters is a bad idea—it makes your code difficult to follow and will inevitably introduce subtle bugs in your controller logic. Augment them, by all means, but leave your existing model values alone, lest you get support calls in the wee small hours and have to debug things.



Handling injection in filters

What if you need a service inside your filter? Filters have the same injection rules as other Grails artifacts, so you can declare the service (or other artifact) as a property in your filter and it will be injected for you. Here’s an example:

class SecurityFilters {
def authService
def filters = {
// then somewhere inside one of your filters
authService.checkAccess(params.userId,
controllerName, actionName)
}
}

5.6.2. Filter URL options

You’ve already seen filters applied to controllers and actions, but there are plenty more options for both fine- and course-grained filtering. First, both controller and action names are subject to wildcarding (and you can wildcard either or both). You can also use Boolean operators to be selective about what you capture.

Let’s look at a few common filtering use cases. This example filters for all actions on all controllers:

myGreedyFilter(controller:'*', action:'*') {
}

This one filters for all actions on the User controller:

myControllerFilter(controller:'user', action:'*') {
}

And the following one filters for just a few actions on the User controller:

mySelectiveFilter(controller:'user', action:'(update|edit|delete)') {
}

But if thinking in terms of controllers and actions is not your bag (perhaps because you’ve done some URL mapping magic for permalinking), you can also use a URI style of mapping in your filters:

myGreedyUriFilter(uri:'/**') {
}
mySelectiveUriFilter(uri:'/post/**') {
}
myParticularUriFilter(uri:'/post/supersecret/list') {
}

The URI-matching mechanism uses Ant-style wildcarding. If you’ve never seen those double asterisks before, they mean “all subdirectories nested to unlimited levels”. One thing to note is that URL mappings fire before filters, so if you were depending on a filter to catch a nonexistent URL, think again. It will return a 404 error and not get to your filter.

That’s quite an arsenal of tools for selective filtering. You’ve now learned the skills to create all sorts of backend intercepting logic for your next application. Whether you’re implementing a custom security mechanism or a stats-tracking filter, or you’re doing some debugging and profiling, filters give you lots of power for fine-grained request interception.

There’s one final feature of controllers that we need to cover: URL mappings.

5.7. Creating custom URL mappings

So far, we’ve followed Grails convention, with URLs translating to /controllerName /actionName/id. But even this convention is configurable through URL mappings.

The /grails-app/conf/UrlMappings.groovy file is shown in listing 5.18. This file is where you configure rules for routing incoming requests to particular controllers and actions.

Listing 5.18. UrlMappings.groovy holds all the URL routing information for your app.
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
"/"(view:"/index")
"500"(view:'/error')
}
}

The $ variables in the UrlMappings file can be confusing, so let’s add a static mapping (permalink) to the file to see how things work:

"/timeline/chuck_norris" {
controller = "post"
action = "timeline"
id = "chuck_norris"
}

With our permalink in place, we can now access the URL /hubbub/timeline/chuck _norris, and it will route us to the PostController and fire the timeline action with an id parameter of "chuck_norris". Note that this isn’t a redirect: the browser’s URL will stay the same, but the controller and action specified in the permalink will fire.

You can also use a more concise version of the syntax:

"/timeline/chuck_norris"(controller:"post",
action:"timeline", id:"chuck_norris")

We find the block-based version more readable, and it also gives you more flexibility (as we’ll see shortly).

Now that we’ve seen mapping blocks, it’s time to get back to those variables we saw earlier.

5.7.1. myHubbub: rolling your own permalinks

You can define how custom variables in URL mappings are passed through as parameters to the controller. For example, it would be great to have a permalink on the Hubbub site to give users a page for their recent posts. Maybe a URL like /hubbub /users/glen could map to all of Glen’s posts, and /hubbub/users/peter could send you off to Peter’s.

One way to achieve this style of permalink is to create a URL mapping like this:

"/users/$id" {
controller = "post"
action = "timeline"
}

This will still call the timeline action of the PostController, but with a params.id value of “glen”, “peter”, or whatever forms the last part of the URL.

5.7.2. Optional variables and constraints

When you define custom variables in your mapping string, you can provide constraints to make sure the value matches a particular string or list.

Suppose we want to provide permalinks for a user’s RSS or Atom feeds. We can implement a feed permalink with an entry like this:

"/users/$userId/feed/$format?" {
controller = "post"
action = "feed"
constraints {
format(inList: ['rss', 'atom'])
}
}

There are two important things to notice here. We’ve made the format portion of the URL optional (by suffixing it with ?), so the user can omit it. If they do supply it, we’ve added a constraints section to ensure that they can only specify “rss” or “atom” as the format. This means /hubbub/users/glen/feed/atom is fine, as is /hubbub/users /glen/feed, but /hubbub/users/glen/feed/sneaky will return a 404 page-not-found error. You can use these constraints to define permalinks with fine-grained URLs.

The rules in your URLMapping file are applied in the order in which they appear, so you can start with more specific rules and fall back to more general ones.

5.7.3. Handling response codes

While we’re on the topic of 404 pages, UrlMappings also gives you great flexibility in mapping response codes to custom pages. If you look in the default mapping file, you’ll notice this entry:

"500"(view:'/error')

This maps the “Error 500: Internal Server Error” code to /views/error.gsp. You can use this mechanism to map any of the HTTP response codes to one of your pages. For example, you could map the standard 500 error to a page inspired by the classic “tweet of death” Twitter 500 page:

"500"(view:'/failWhale')

If you want your errors to be handled by a controller action instead of directly by a GSP, that’s supported too. This might be convenient for keeping stats on which URLs keep 404ing on your site. Here’s how you could configure the 404 error code to be handled by a dedicated errors controller:

"404"(controller: "errors", action: "notFound")

5.7.4. Mapping directly to the view

There are situations where you might want to map a URL directly to a view and bypass any controller logic. The classic example is your application’s home page, which you might implement like this:

"/"(view:"/homepage/index")

Notice that you don’t include the .gsp extension when you construct the mapping.

5.7.5. Wildcard support

URL mappings can also support greedy wildcards using Ant-style wildcards. This is particularly useful when you impersonate filenames in your backend.

For example, if you generate PDFs dynamically, but want to provide permalinks on your site, you might do something like this:

"/documents/$docname**.pdf"(controller:"pdf", action:"render")

The wildcard option lets you match /documents/release-notes/myproject.pdf as well as /document/manuals/myproject.pdf. In both cases, you’ll get a docname parameter that you can use in the controller action. The docname will contain the relative path that $docname matches (for example, release-notes/myproject and manuals/myproject). This capability is convenient for developing content management systems (CMS) where you generate the PDF based on dynamic data in a domain object.

And that’s the end of our exploration of UrlMappings. We’ve finished all you need to know about controllers. It’s time to review what we’ve taken in.

5.8. Summary and best practices

In this chapter, we’ve explored a mountain of skills and techniques related to controllers.

We started by implementing a timeline and addPost feature for Hubbub. We then refactored our posting operations into a PostService that we’ll reuse later in the book. After tidying up our posting logic, we looked at all sorts of data-binding techniques, including whitelisting, blacklisting, error handling, and command objects.

We then had some fun with custom controller content types while we implemented our profile page and handled photo uploads. Finally, we learned about backend logic and using filters and UrlMappings.

Let’s pull out some of the key practices to take away from the chapter:

  • Use flash scope. Flash scope is ideal for passing messages to the user (when a redirect is involved).
  • Use the errors object wisely. Make use of the errors object on your domain class to display validation messages. Take advantage of resource bundles to make error messages relevant to your application use cases.
  • Use command objects. Take advantage of command objects for form submissions. Don’t just use them for validation—they can also be handy for encapsulating tricky business logic.
  • Understand data binding. Data-binding options in Grails are plentiful and subtle. Understand how data binding works for child objects when form parameters are prefixed. Use whitelisting to ensure that data binding doesn’t compromise sensitive fields.
  • Be forgiving with URLs. Use default actions to make URLs more forgiving, and do the same for custom URL mappings. Permalink-style URLs are much easier to remember and not difficult to implement.
  • Apply filters. Employ filters when you need to selectively fire backend logic based on URLs or controller-actions combos.

We’ve learned a lot about the internals of controllers in this chapter, and in the next chapter we’ll build on our knowledge by implementing some fine-looking views to give Hubbub some visual sizzle.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset