Building a blog with Grails - Tutorial 6

By the end of tutorial 5 we had logins to the admin section of our app working and the admin index action displaying our posts. Well, our one, single post ( unless you've modified your dataset ).

We need to be able to create new posts by using some sort of GUI in our administrative section. That's what tonight's tutorial will start. I'd like to have put the entire process in one tutorial but things this week haven't really been working in my favor. So I'm separating it into pieces.

In other news, this tutorial series was mentioned by the folks at Grails Podcast. I really appreciate the positive words they had and hope they'll be following the series.

In case you're curious, this is where Topeka, KS is:


On to the tutorial . . .

When in comes to creating a post, we want the user to be able to "write" HTML and save it to our database. In terms of a GUI we have a couple options: use an HTML textarea tag or use some kind of plug-in that facilitates wysiwyg functionality. If you look at other, well-known blogging platforms ( MT, Wordpress ) they're using wysiwygs.

Initially, I started working with the FCK Editor Plug-In. However, even though it was relatively simple to use, I wanted to incorporate a plug-in that I would use much more frequently because of it's breadth of uses.

As I mentioned in the opening post of this tutorial, I would at some point start incorporating some type of Rich GUI plug-in. Therefore, I decided that there's no better time than the present to get busy with the Grails RichUI Plugin. After you've taken a look at it I think you'll understand why I opted for it rather than just simply adding the FCK Editor. There exists a plethora of functionality that I will soon be looking to implement that the RichUi plug-in provides - including a rich text editor.

So yeah, I lied. But I'm moving forward with it anyway.

Installing the Grails RichUI Plug-in:

Right click on the Project name and then click on "Grails Plugins..."



Once that's done, a dialog should open. Click on, "New Plugins." You'll be able to select from a wide variety of plug-ins after the list is populated:



Scroll down the list ( it's arranged alphabetically ) until you find rich-ui: ( I know there's something different highlighted in the image below - when the list of "New Plugins" populates it does not display the plugins you have installed. I forgot about this, and since I installed before trying to take a screen shot - well . . . )



With that done, click on "Install" and the necessary procedures will take place. Afterwards click "Close" and then we can move on.

An Action and a View

With our plug-in installed we can plow forward into our action and view. Open the AdminController and create an action called, "create_post." It should look something like this:

def create_post = {

}


We'll get back to that in the next installment of this tutorial, first we have quite a bit of work to do in our view. Not only will implement our plug-in tags in our view, we'll also get to use a new tag that we'll have to set up in our messages.properties file.

First, create a file under "Views and Layouts/admin" called "create_post." Remember, you don't have to supply the ".gsp" part of the file in Netbeans. It'll do that for you. After that's done you will want the contents of that file to match the following:

<html>
    <head>
        <title>
            <g:if test="${blog}">${blog?.name}</g:if>
        </title>
        <meta name="layout" content="admin" />
        <resource:dateChooser />
        <resource:richTextEditor />
    </head>
    <body>

        <div id="alpha">
            <h1>Create a new Post</h1>

            <g:form method="post" action="create_post">

                <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="dd.MM.yyyy" value="
${post?.publishDate}" />
                        </td>
                    </tr>

                    <tr>
                        <td colspan="2">
                            <richui:richTextEditor name="body"
                               value="${post?.body}" width="525" />
                        </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 colspan="2">
                            <g:submitButton name="edit" value="Edit!" />
                        </td>
                    </tr>

               
                </table>
            </g:form>

        </div>

        <div id="beta">
            <h3>Categories</h3>
            <g:select name="subject" from="${Subject.list()}"
value="${id}" optionKey="id" />

            <br clear="all" />

            <h3>Status</h3>
            <g:select name="status" from="${['P', 'R', 'U']}"
                      valueMessagePrefix="post.status" />
            <br clear="all" />

            <span>Accept Comments:</span>
            <g:checkBox name="acceptComments" />
            <br clear="all" />

            <span>Accept Trackbacks:</span>
            <g:checkBox name="acceptTrackbacks" />

        </div>

    </body>
</html>


Notice at the beginning of the file, two tags:

<resource:dateChooser />
<resource:richTextEditor />


These tags import the necessary CSS and JavaScript files to facilitate the date chooser and rich text editor that we will be using instead of the options available without the plug-ins. Since we've already seen some of these tags before, I'm going to skip going over the form and textField tags. However, let's go over the next tag:

<richui:dateChooser hourStyle="width:30px;"
minuteStyle="width:30px;" name="publishDate" time="true" format="MM/dd/yyyy" value="${post?.publishDate}" />


This tag, from the Rich-Ui plug-in, is going to build our date chooser. The only required attribute is the name however, I've supplied the hourStyle and minuteStyle to shorten the width of the inputs that will be rendered to accept the minute and hour values. Also time has been set to true so that the User can provide the time the Post is to be published. Lastly, the date format ( formatted according to the SimpleDateFormat class ) is provided in the manner I want the user to view it.

<richui:richTextEditor name="body" value="${post?.body}" width="575" />

The next new tag is the richTextEditor tag from the Rich-Ui plug-in. The name attribute is required, but I've also supplied the value and the width of the rendered editor. I could have also supplied the type attribute so that a different editor with more features available to the user would have been rendered.

Notice that I am only using a textField tag to allow the user to input the Tags associated with this Post. Also, for now, I'm setting the name of the tag to "tag_list". Perhaps you don't remember this property from the Post domain class. That's because it doesn't exist yet. We'll add it this way ( in your domain class, Post ):

static transients = ['tag_list']
String tag_list


Basically, what we're telling Grails here is that we want to add a property called tag_list, but we don't want to use it in the database. Therefore, our post table won't have a column named, "tag_list" but our domain class will have a property that can be accessed.

<g:select name="subject" from="${Subject.list()}"
value="${id}" optionKey="id" />


Next, up is the Grails select tag. You have quite a few options available to use this tag. What's being done above is that, as you have seen before in actions, we're getting a list of Subjects with which we populate the options. The value of the option will be the id of each Subject from the database. The property displayed to the user ( what they see in the drop down ) will be whatever the domain class' toString() method returns. In this case it is the "name" property.

<g:select name="status" from="${['P', 'R', 'U']}"
                      valueMessagePrefix="post.status" />


This select tag is built differently than our first one. We are using values stored in the messages.properties file. Why am I doing it this way? Because I don't want to have to store this information in a database and handle it dynamically. This blog software will treat different statuses of posts differently and that isn't something I want changed. So, statuses are essentially static.

In your messages.properties ( found under "Message Bundles" if you are in the "Projects" view in Netbeans ) file insert the following:

post.status.P=Published
post.status.R=Pending
post.status.U=Unpublished


As you can see there are three different values along with three different ids. Essentially, when our select tag builds, it will draw from those matching "post.status" entries in the messages.properties files using those values after "post.status." as the value for the options and the value displayed to the User will be the that which each entry in the messages.properties file is set to.

 <g:checkBox name="acceptComments" />

The last tag we'll go over is the checkBox tag. As you might expect, it renders an HTML checkbox. We have one for the boolean value of acceptComments ( whether or not the author wants to accept comments on the post they are writing ) and one very similar one for allowing trackbacks.

Aside from prettifying it, our view is complete. Since we have our administrative area forcing us to login we can start our application, and browse to http://localhost:8080/GroovyBlog/admin, login and then browse to http://localhost:8080/GroovyBlog/admin/create_post and we should see the following:



Everything is rendering as it should - even though it's about as ugly as it can be. Perhaps one day we can work on beautifying it, but for now it's the functionality that I'm concerned about.

So tonight we installed a plug-in and worked up our view that will enable users to enter posts. In the next installment we'll tackle the action as there's quite a bit of work to do processing all the data the user inputs through the form we made.

As usual, leave any comments you feel so inclined to share and move on to the next tutorial.
OpenID accepted here Learn more about OpenID

About this Entry

This page contains a single entry by Jim published on April 14, 2009 10:21 AM.

Something to think about the next time you order Dominos Pizza was the previous entry in this blog.

The joy of sex in the library is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.