Changes
- Page 2 - Under Groovy Installation. It maybe unclear but there are platform specific installers for Windows, Ubuntu and Debian.
- Page 14 - Listing 2-7 line 3.
String args[create
] may not work with all groovyc compilers but it does work with javac. If you run into an issue try String[create
] args.
- Page 14 - Listing 2-8 line 3.
{;} is appropriate for the Windows platform. If you are on Linux, Unix or Mac OSX, you will need to replace {;} with {:}.
Line 03 could also be written like the following without java.util
return {println "${initialDate} - ${new Date()} : Elapsed time
- Page 30 - Listing 2-27 line 15.
There should not be an S on that line.
- Page 30 - Listing 2-27 line 24 should be:
- Page 36 - Listing 2-30 line 03 is missing a quote and should read as follows.
03 assert "abcabc" ==~ /abc/ // Fails - not an exact match
- Page 36 - In the last paragraph it should say, "A group is defined within..."
- Page 39 - Listing 2-34 Line def matcher = phonePattern.matcher(phoneStr) should be def matcher = phoneRegex.matcher(phoneStr)
- Page 41 - Listing 2-35 3rd line of code from the bottom should say:
list.collect{it.printlnFullName()}
- Page 42 - Note: Says Listing 2-35 includes a new technique named parameters but it was actually introduced in Listing 1-2 on page 6.
- 97 - The Todo application does not work with Grails 1.1 as the Category domain collides with groovy.lang.Category. To make the application work rename the Category to something else like CategoryItem, put it into a package or rename it Group which would require a mapping since Group is a reserved word in SQL.
- Page 110 - Create the Topbar section first paragraph should say grails-app/views/common.
- Page 114-115 listing 5-9, The rendering of the topbar template misses the div tag around it.
It should be,
<div id="topbar">
<g:render template="/common/topbar" />
</div>
- Page 123 Listing 5-11 lines 16 and 29 should read.
<g:form… instead of <form..
and
</g:form> instead of </form>
- Page 123 - Due to a bug fix in Grails 1.0.3 the actionSubmit on line 26 of Listing 5-11 should be the following:
<span class="button"><g:actionSubmit value="Login" action="handleLogin"/>
- Page 125 - Due to a bug fix in Grails 1.0.3 the handleLogin action in Listing 5-13 does not work any longer. The new implementation is:
def handleLogin = {
def user = User.findByUserName(params.userName)
if (!user) {
flash.message = "User not found for userName: ${params.userName}"
redirect(action:'login')
return
} else {
session.user = user
redirect(controller:'todo')
}
}
def handleLogin = {
def user = User.findByUserName(params.userName)
if (!user) {
flash.message = "User not found for userName: ${params.userName}"
redirect(controller: 'user', action:'login')
return
} else {
session.user = user
redirect(controller:'todo')
}
} def logout = {
if(session.user) {
session.user = null
redirect(controller: 'user', action:'login')
}
}
- Page 140 Listing 5-21 should be:
<div id="menu">
<nobr>
<g:if test="${session.user}">
<b>${session.user?.firstName} ${session.user?.lastName}</b> |
<g:link controller="user" action="logout"><g:message code="topbar.logout" /></g:link>
</g:if>
<g:else>
<g:link controller="user" action="login"><g:message code="topbar.login" /></g:link>
</g:else>
</nobr>
</div>
{/code}
* page 149 Listing 5-30
There have been several reports of issue with the if statement. As written, it assumes
that the user is logged in. There is also a type conversion issue in comparing session.user.id (Long) to params.id (String).
You may want to update the code as follows:
if (session.user?.id as String != params.id) {
{code}
Notice the ? Null safe dereference and casting to String for comparison.
- Page 155 - The URL at the bottom (#21) no longer is valid. The new URL is - http://groovy.codehaus.org/Strings+and+GString
- Page 162 - As of Grails 1.0.3, the last line of grails.app="error,stdout" will error at compile time. Simply remove it and configure individual artifacts as appropriate.
- Page 179 - First code snippet has a quote in the wrong place and should read:
id composite:[create
'name','dueDate']
- Page 180 - 'DBAs can then these by hand in the database' should read 'DBAs can create these by hand in the database'.
- Page 181 - tablePerHierarchy should be true.
- Page 184 - the autoTimestamp should be true in order to have the auto time stamp automatically on.
- Page 187 - "In our application, we will use quite a bit of ..." should "In our application, we will use quite a lot of ..."
- Page 199 - Chapter 6, page 199, listing 6-30: the description of the Todo.findAllByPriorityOrStatus("2","4") should read 'in the second, you're separating the retrieval with an Or, so that if a record has a priority of "2" or a status of "4".'
- Page 200 - The description in the last paragraph is slightly inaccurate. An offset of 20 with 10 records will result with records from 20 to 29 not 20 to 30.
- Page 209 - class TodoServiceService should have been defined as TodoService
- Page 255 - In Listing 7-12 where we display the first name and last name with ${session.user?.firstName} ${session.user?.lastName} is not technically incorrect. However it does require the user to have user object stored into the session via a filter. A better way to do this that uses pure acegi tags is - <g:loggedInUserInfo field="firstName"/> <g:loggedInUserInfo field="lastName"/> . With that code the first name and last name is grabbed directly from whatever acegi user object we have defined.
- Page 266 - Listing 8-6
dueDate (should be file or associatedFile) and asociatedFile (should be associatedFile)
<tr class='prop'>
<td valign='top' class='name'><label for='dueDate'>File:</label></td>
<td valign='top'
class='value ${hasErrors(bean:todo,field:'asociatedFile','errors')}'>
<input type="file" name="asociatedFile" />
</td>
</tr>
- Page 278 - In the list of g:javascript options, "yahoo" no longer is valid. You have to pass in the option "yui". In addition you will now have to download yahoo UI much like DOJO. In order to install the yahoo UI run "grails install-yui"
- Pages 300 & 302 - Grails 1.0.3 made a change that causes the requested URL Mapping parameters to get added to the params lists even if the controller or other URL Mapping parameter is over written. There for line of one listing 9-5 on page 300 should be:
"/$rest/$domain/$id?"{
And the second line of code on page 302 in listing 301 should be:
domainClassName = capitalize(params.domain)
- Page 323 - Under Compiling the Report section, the collab-todo/web-app/reports directory may not exist so you should create it.
Using Examples with Eclipse
Unfortunately, the Eclipse Groovy plug-in is not by default prepared to run Grails applications using the Grails generated launcher. Here are the things you need to do to configure Eclipse and the examples to work in Eclipse.
- Set GRAILS_HOME Classpath Variable to a local Grails 1.0.3 intallation.
- In the project's Groovy Project Properties check the Disable Groovy Compiler Generating Class Files.
- Configure the project's JRE to be a full JDK including the tools.jar.
See
http://grails.org/Eclipse+IDE+Integration for more details.
Submitting Errata
If you find any errors send us an email at - authors@beginninggroovyandgrails.com