Groovy/Grails Talk
Home     Login     Register
Viewing category: GSP, Tags & Templates
Thursday, 27 August 2009
Book - Grails 1.1 Web Application Development - Part 12
Chapter 11 - AJAX and RIA Frameworks

With Grails built-in support for AJAX and the power supplied by the RichUI plugin, we are able to take the tagging framework implemented in the previous chapter to new heights. We add in-line editing of our tags, auto completion and a tag cloud.

The chapter begins with adding in-line editing. We learn that Grails uses the Prototype framework for the AJAX support. We are given an overview of the remoteLink and formRemote tags, including a table describing the attributes. After a discussion of the user actions and the controller actions that will be needed to handle those actions, we create a TaggableController implementing the requisite actions. We then move on to add a couple in-line forms that will be used to render the edit and show tags views. Next we make slight modifications to the _message.gsp and _file.gsp templates. Finally, we are instructed to add the prototype library to the main template. This was quick and simple.

From there we move on to the addition of auto-complete capabilities to our tag lookup, creation and editing. The author tells us that there are two plugins available: GrailsUI and RichUI. They both wrap the YUI auto-complete widget. Jon chooses to use the RichUI plug-in as it has more features than the GrailsUI plug-in and the default styling is more appropriate for the application. After installing the plug-in, we add two methods to the TaggableController: suggestTags and renderAsXml. The latter method is the more interesting of the two. It uses the render method, but instead of specifying a view or a template, a closure is specified. The closure is executed against the Groovy MarkupBuilder. Since this is a little difficult to conceptualize, Jon provides a concrete example. This is good, but, personally, I would have preferred to see it as a test or an assert at a minimum. Asserts are a great way to explore the language. At this point, we are introduced to two new tags provided by the autoComplete widget: resource:autoComplete and richUI:autoComplete. This is followed by a table describing the attributes available to the autoComplete tag. With this new found knowledge, we update the message create.gsp, the taggable editTagsForm template, the profile myTags view with the richUI:autoComplete tag. We are then directed to add the resource:autoComplete tag to the main layout head element. The author suggests booting up the application and testing the auto-complete feature at this point. Sure enough, it all works as desired.

Now we are able to add tag clouds. We get a brief discussion of just what a tag cloud is and a sample based upon the words contained in the chapter. We are also given reasons why adding a tag cloud makes sense. Again, we use capabilities provided by the RichUI plug-in. We are presented with a static example from the online plug-in documentation and are encouraged to place it into one of our pages and then view the page. As you would expect, we get a nice little cloud. This is made possible through the richUI:tagCloud tag. We are also provided a table describing the attributes for the tag. Most of the work involved in implementing the tag cloud comes in areas other than the actual rendering of it. We add method cloudData to the TagService class. We then update the MessageController by injecting tagService and contentService, modifying the list method, and adding a filterByTag method. The FileController is similarly modified, however there is a trick to list method. Here we use listDistinct method on the CriteriaBuilder. This is necessary, we are told, because Hibernate uses an outer join to perform eager featches on multiple cardinality relationships. Finally, we get to changing the message and file list views. These are simply the aforementioned richUI:tagCloud added to a div element. And, Presto! We have a tag cloud!

This chapter went very smoothly. There was only one small issue I found and was irrelevant. The chapter clearly demonstrates the power of plugins to make very user friendly interfaces.

Part 1 of this series can be seen here.
Part 2 of this series can be seen here.
Part 3 of this series can be seen here.
Part 4 of this series can be seen here.
Part 5 of this series can be seen here.
Part 6 of this series can be seen here.
Part 7 of this series can be seen here.
Part 8 of this series can be seen here.
Part 9 of this series can be seen here.
Part 10 of this series can be seen here.
Part 11 of this series can be seen here.


Posted by Bill Turner at 07:03 AM
Sunday, 16 August 2009
Book - Grails 1.1 Web Application Development - Part 11
Chapter 10 - Managing Content through Tagging

This chapter continues building the application by adding tagging capabilities. Achieving this requires that we learn how to work with inheritance in domain classes, understand the available GORM persistence strategies, and gain insight into polymorphic queries over domain inheritance hierarchies. We also need to use manage collections using collect and sort to get the behavior we want.

Initially we are given an overview of just what tagging is, and quickly move to a domain model needed to support tagging. After creating the initial model of Tag and Tagger, we create TagService. This provides methods for adding tags and is where we use the collect method. We are also shown the Elvis operator. A bit of trivia explains that the name for this operator comes from the fact that it looks Elvis' hair style. The author then has us write some integration tests to verify that all is working properly. We are required to implement further functionality in the Message class to make the tests pass.

After making changes and having the tests pass successfully, we turn our attention to tagging File classes. Here is where we learn GORM supports two of the several Hibernate inheritance persistence strategies, table-per-hierarchy and table-per-subclass. The former creates one table per hierarchy and is the Grails default. The latter creates one table for each class in the hierarchy. Table-per-hierarchy has a drawback; a number of columns will have to be nullable. To override the default behavior, we are told to add the mapping property to the parent domain as follows:
static mapping = { tablePerHierarchy false }
In order to implement tagging File objects, we re-examine the domain model and add a superclass to Message and File called Taggable. We then add another test and quickly discover that our tests fail. This is due to the fact that the polymorphic nature of our queries returns all Message and File objects with the given tag even though we think we are querying objects of the specific type. This is remedied by adding another method on the Taggable class, and adding nearly identical methods to Message and File that override the finder method on Taggable.

Once the domain and persistence logic is coded and tested, we move on to modifying the user interface. Jon discusses templating in Grails. In Grails, a template is the same as a GSP except that it is prefixed with and underscore. He shows the various ways templates are rendered and provides a warning regarding rendering a collection via the template. He states that we must be careful to pass in the actual collection by using the ${} notation.

As we closeout the chapter, we create another service, ContentService and make greater use of templating. The added templating allows either Message or File posts to be displayed interchangeably. These final touches allow us to create a homepage wherein the user can specify which tags are of interest. The view will display the five most recent updates, either messages or files, and the five most recent items of interest, again, either messages or files.

Throughout this chapter, there were few problems. In a few tests a user variable named fred is used that was not defined elsewhere, nor is the variable used in the book source. Again, as he has done in previous chapters, he references a view named post where none exists. And, he continues to unnecessarily use some optional things such as the access modifier public. These are all rather trivial issues.

Part 1 of this series can be seen here.
Part 2 of this series can be seen here.
Part 3 of this series can be seen here.
Part 4 of this series can be seen here.
Part 5 of this series can be seen here.
Part 6 of this series can be seen here.
Part 7 of this series can be seen here.
Part 8 of this series can be seen here.
Part 9 of this series can be seen here.
Part 10 of this series can be seen here.

Posted by Bill Turner at 08:39 PM
Friday, 31 July 2009
Book - Grails 1.1 Web Application Development - Part 9
Chapter 8 - More GORM and Criteria

Part 1 of this series can be seen here.
Part 2 of this series can be seen here.
Part 3 of this series can be seen here.
Part 4 of this series can be seen here.
Part 5 of this series can be seen here.
Part 6 of this series can be seen here.
Part 7 of this series can be seen here.
Part 8 of this series can be seen here.

Chapter 8 builds upon our application by adding file versioning capability to our file sharing system. This provides the excuse to revisit GORM and criteria queries as promised in an earlier chapter.

As we start the chapter, file sharing is modeled through two domains, File and FileData in a 1:1 relationship. Here we add FileVersion. FileVersion takes on all the responsibilities that File had, while File creates a hasMany property for the versions. In order to achieve the capability of retrieving the versions in the desired order, the author added a SortedSet property using the same name as the container specified in the hasMany map for the versions. In order to allow this ordering, FileVersion had to implement the Comparable interface and a compareTo method. Jon used the public access modifier on the compareTo method, which is unnecessary in Grails. It was nice having implementation of an ordered relationship between the two domains.

After the requisite changes and additions were made, File is 1:m to FileVersion, and FileVersion is 1:1 to FileData. With this change, it became necessary to change how data was retrieved on the home page. This lead to the discussion of criteria queries. The first thing the author did was to show three dynamic queries from chapter 5 and the equivalent versions written using criteria. This clearly demonstrated how criteria queries are built. He then explains that nodes within the criteria can be used to specify logical operators and to query across associations. For the latter, a property added to File meant to hold a reference to the current FileVersion was used in demonstration. He also discussed the use of FetchMode as we still want to retrieve the User eagerly from the current version. After providing two tables, one a criteria reference, the other a listing of logical criteria operators, we are shown the use of criteria properties, in this case, limiting the results of our File query to ten. He closes the discussion of criteria queries by providing links to the Hibernate Criteria Javadoc, and informing us of and providing links to documentation on Projections and Scrollable Results.

At this point, we are directed to modify the save method in the FileController. Here we run into a problem. The code listing on page 160 meant to display the errors does not work. In the listing, a view of post is referenced. No post view has been created thus far, nor is it contained in the downloaded source. The downloaded source references create as expected. Worse, though, is that by changing the model here from file to currentVersion breaks causes no messages to be displayed on an upload error. The problem is that the save is done on the File object and the Error object is bound to that, not to currentVersion. There are multiple solutions to this. One possible solution is to add a line just before the render to set the current version error object to the file error object. This is shown below.
if (file.save()) {
flash.userMessage = "File [${currentVersion.name}] has been uploaded."
redirect(controller: 'home')
}
else {
currentVersion.errors = file.errors
render(view: 'create', model: [file: currentVersion])
}

However, this smells to me. Rather, the preferred change in my opinion is to the create.gsp. Here the code currently reads:
< g:hasErrors bean="${file}" >
< div class="validationerror" >
< g:renderErrors bean="${file}" as="list" / >
< /div >
< /g:hasErrors >

Change this to:
< g:hasErrors >
< div class="validationerror" >
< g:renderErrors as="list" / >
< /div >
< /g:hasErrors >

After writing the rather complex save logic in the controller, Jon tells us that he understands it is complex and difficult to test. He states that we will be moving much of this logic to a service in the chapter.

The chapter is closes with the required changes to our home page and message properties, and by updating the download method in the FileController.

I have to admit to being a bit frustrated by the errors encountered, though most books do seem to have some problems. None encountered so far have been insurmountable to me, but a noob may be really dazed and confused. Then again, problem solving is a great way to learn. If you feel that way, I suggest you download the free version of Jason Rudolph's mini-book Getting Started with Grails available at InfoQ, which was based on very early version of Grails and Groovy.
Posted by Bill Turner at 08:53 PM
Thursday, 2 July 2009
Book - Grails 1.1 Web Application Development - Part 4
Chapter 3 - Posting Messages

Part 1 of this series can be seen here.
Part 2 of this series can be seen here.
Part 3 of this series can be seen here.

The beginnings of the business goals of the project are implemented with this chapter. We create a new domain, Message, two views, one for adding messages, the other for viewing, along with corresponding controllers. Along the way, we learn about binding, validation and other user messages, the flash scope, redirection, the domain list method, several gsp (Groovy Server Pages) tags, layouts including the main.gsp and how SiteMesh renders layouts, and securing the site from XSS (cross site scripting) attacks.

There were a few small mistatements or errors. First, when explaining how dateCreated and lastUpdated properties can be added to domains and will be updated for free, he states that they must have the corresponding constraints set to nullable:true. The corresponding example shows this, as well. Setting these properties to null is unnecessary. To be fair, this could've been true in an earlier release of Grails.

The second issue is really minor. At one point Jon suggests you use the BootStrap.groovy to create some initial messages then says you can view the home page and see these messages. What he fails to mention is that the application needs to be restarted to pick up the changes to the BootStrap.groovy (unless that was just some strange issue on my side, but I think not).

The final error was when HTML encoding was discussed. We are instructed to make the highlighted changes, though the code sample has no highlighting. I trust experienced developers can overcome this.

In earlier chapters we were introduced to some command line arguments for creating domains and controllers. In this chapter, however, we are never introduced to generate-views. I thought this curious. Yes, generate-views would create several unneeded views, but I feel this being an introductory text, it would be better to demonstrate the command and direct the reader to delete the unnecessary views. The positive side of having the reader hand code the views is that it makes it far more obvious how various code fragments relate to the other parts of the application, as well as the introduced GSP tags.

At the end of this chapter, the reader should now have an understanding of the basic building blocks of Grails. This chapter covered a lot of territory. Even so, it seemed simpler than the previous chapter, likely because domain development is so fundamental to most applications. Readers should have at this point a good idea of how rapid development can be with Grails.
Posted by Bill Turner at 12:00 AM
sun mon tue wed thu fri sat
    1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30   

Latest Posts
Archives
Categories
Bookmarks
Authors
Search
Syndicate This Site
Add to Technorati Favorites