Given the shortage of time that so often accompanies weekdays I've decided that I'm going to post these tutorials on Friday or Saturday nights - depending upon the complexity of the tutorial. It takes time to format them, make sure they're done without big errors and take all the screen shots. Also, I thought that would be a little more helpful to those that are following along.
With that out of the way, let's recap what went on last time. In a nutshell it finally became possible to create a new post on the blog. Of course there were a few things that had to be done in order to facilitate that. We installed the Grails RichUI plug-in. That gave us a WYSIWYG editor and an aesthetically pleasing widget to enter the date of the post. We also created a new action to facilitate creating new posts. However, in keeping with MVC design, we didn't put our post-creating logic in our controller - we put it in a service.
Tonight we're going to do much of the same stuff. We're going to make it possible to select a post from our admin index view and edit it. In order to do that we'll have to create a new view for editing, a new action, modify our admin index view and add something new to our service.
Let's get busy . . .
First we're going to make an adjustment to our admin index view.
<g:each in="${posts}">
<tr>
<td>
<a href="${createLink(controller:'admin', action:'edit_post', id:it.id)}">${it.title}</a>
</td>
<td>${it.author.username}</td>
<td>${it.publishDate}</td>
</tr>
</g:each>
We're going to edit the view inside our the iteration that displays each of the posts. Notice on line 4 that we're creating a link to the action ( which we'll soon be creating ) using the createLink method. We've used this before, but this time we're passing something extra to the action we're calling. Since we know the id of the post that needs editing, we're going to pass that along. What we'll end up with is a link that looks like this: http://locahost:8080/GroovyBlog/admin/edit_post/1. The id of the post will be passed as a parameter that we can use to grab the post that needs editing from the database.
The
edit_post view:
<html>
<head>
<title>
<g:if test="${blog}">${blog?.name}</g:if>
</title>
<meta name="layout" content="admin" />
<resource:dateChooser />
<resource:richTextEditor />
</head>
<body>
<g:form method="post" action="edit_post" id="${post?.id}">
<div id="alpha">
<h1>Admin - Edit</h1>
<g:hasErrors bean="${post}">
<div class="errors">
<g:renderErrors bean="${post}" as="list" />
</div>
</g:hasErrors>
<table>
<tr>
<td>
<label for="title">Post Title:</label>
</td>
<td>
<g:textField size="50" id="title" name="title"
value="${post?.title}" />
</td>
</tr>
<tr>
<td>
<label for="title">Post Date</label>
</td>
<td>
<richui:dateChooser hourStyle="width:30px;"
minuteStyle="width:30px;" name="publishDate"
time="true" format="MM/dd/yyyy" value="${post?.publishDate}" />
</td>
</tr>
<tr>
<td colspan="2">
<richui:richTextEditor name="body"
value="${post?.body}" width="575" />
</td>
</tr>
<tr>
<td>
<label for="tag_list">Tags:</label>
</td>
<td>
<g:textField id="tag_list" name="tag_list"
value="${post?.tag_list}" />
</td>
</tr>
<tr>
<td>
<label for="keyword_list">Keywords:</label>
</td>
<td>
<g:textField id="keyword_list" name="keyword_list"
value="${post?.keyword_list}" />
</td>
</tr>
<tr>
<td colspan="2">
<g:submitButton name="edit" value="Edit!" />
</td>
</tr>
</table>
</div>
<div id="beta">
<h3>Categories</h3>
<g:select name="subject"
from="${Subject.list()}"
value="${id}"
optionKey="id"
value="post?.subject"/>
<br clear="all" />
<h3>Status</h3>
<g:select name="status"
from="${['P', 'R', 'U']}"
valueMessagePrefix="post.status"
value="post?.status"/>
<br clear="all" />
<span>Accept Comments:</span>
<g:checkBox name="acceptComments" value="${post?.acceptComments}" />
<br clear="all" />
<span>Accept Trackbacks:</span>
<g:checkBox name="acceptTrackbacks" value="${post?.acceptTrackbacks}" />
</div>
</g:form>
</body>
</html>
There's nothing super-spectacular going on in our new view. As a matter of fact, it is very similar to our create_post view. The only remarkable difference is that any input that did not have the value set is now being set with the appropriate property of the post. However, the one big difference is this:
<html>
<head>
<title>
<g:if test="${blog}">${blog?.name}</g:if>
</title>
<meta name="layout" content="admin" />
<resource:dateChooser />
<resource:richTextEditor />
</head>
<body>
<g:form method="post" action="edit_post" id="${post?.id}">
Obviously we've changed the action that should be called when the form is submitted. But, we also made sure ( on line 12 ) that when the post is submitted the id of the post will also be sent to the action.
We'll start out our action like so:
def edit_post = {
def post = Post.get(params.id)
[post:post]
}
With this code in place we should be able to run our app, login, select a post to edit and be forwarded to the edit_post view which will render correctly:

The only thing missing are our two variables,
tag_list and keyword_list. We can fix that with a little code but where best to put that code? Again we'll follow the convention of not putting business logic in our controller. It could be argued that this is not business logic, but I would argue otherwise. I'm going to create another method in our PostService to handle this kind of stuff. You never know, we might end up needing other kind of processing to occur and that would mean putting it in the controller or repeating it in many controllers:We'll modify our controller like so:
def edit_post = {
def post = postService.getPostForEdit( params.id )
[post:post]
}
And our new service method will look like this:
def getPostForEdit( id ) {
def post = Post.get( id )
if( post ){
def i = 1
post.tag_list = ''
post.tags.each {
println ' i: ' + i
if( post.tags.size() == i) {
post.tag_list += it.name
}else {
post.tag_list += it.name + ', '
}
i++
}
i = 1
post.keyword_list = ''
post.keywords.each {
println ' i: ' + i
if( post.keywords.size() == i) {
post.keyword_list += it.name
}else {
post.keyword_list += it.name + ', '
}
i++
}
return post
}
else {
return null
}
}
With that done our two properties will be displayed as they should so that they can be edited:

What we need to do now is create a method on our service, much like the one that created our post to edit our post:
Here's the complete code from the new service method. There's not a big difference from the code used to create our post. All that's really changed is that instead of creating a "new" post we get the post from the database and repopulate the variables based on the one's passed through the params.
Also there's a fix to a flaw in how the tags and keywords are created. On lines 17, 19, 28 and 30 you'll see that we need to call the
trim() method to take the spaces off either end of the variable. Otherwise we'll end up creating new tags and keywords when we don't need them. It would probably be a wise decision to do the same thing in our createPost as well.
def editPost( params, user ) {
def blog = Blog.get(1)
def post = Post.get( params.id )
post.properties = params
post.extendedBody = ''
def title = post.title
post.slug = title.replaceAll('[^A-Za-z0-9\\s]','')
post.slug = post.slug.replaceAll('\\s','-')
post.author = user
def tag_list = params.tag_list.split(',')
def tags = []
tag_list.each {
def tag
tag = Tag.find( "from Tag as t where t.name = ?", [it.trim()] )
if( !tag ){
tag = new Tag( name: it.trim() )
}
tags.add( tag )
}
def keyword_list = params.keyword_list.split(',')
def keywords = []
keyword_list.each {
def keyword
keyword = Keyword.find( "from Keyword as k where k.name = ?", [it.trim()] )
if( !keyword ){
keyword = new Keyword(name:it.trim())
}
keywords.add( keyword )
}
def subject = Subject.get( params.subject )
if( post.validate() ){
post.addToSubjects( subject )
tags.each {
def t = it.save()
post.addToTags( t )
}
keywords.each {
def k = it.save()
post.addToKeywords( k )
}
post = post.save()
}
return post
}
Here's the complete code to our new controller action. Notice that changes have been made because the controller will behave differently depending upon the request method:
def edit_post = {
if( request.post ) {
def user = User.get( session.user.id )
def post = postService.editPost(params, user)
if( post.hasErrors() ){
flash.message = 'There are errors'
flash.post = post
render(view:'edit_post',model:[post:post])
}
else {
flash.message = 'The Post was edited successfully'
redirect(controller:'admin', action:'index')
}
}
else {
def post = postService.getPostForEdit( params.id )
[post:post]
}
}
Now when we run our app and modify the properties of the post we will be able to see that the changes are being applied as input. The only thing that is missing is the ability to set the Subject of the post as well as applying multiple Subjects to a single Post. Another thing I'd like to be able to do is allow the user to be able to input their tags using an auto-complete field. In order to accomplish that kind of functionality, however, we'll have to use some Ajaxy kind of stuff to accomplish that. That's a whole tutorial in and of itself. So until next time . . .
As usual - leave some comments dammit!

Just finished tutorial 8. I really like what you are doing. Please keep it up.
Thanks for the feedback. The next one will be up within a few days or so. I needed to take the weekend off - badly.
Jolly good tutorial. I look forward to seeing some ajax stuff.