Monday 18 April 2011

Grails part 2 - First Project

In my last post we talked a little bit about the web framework known as Grails and went through the steps required to get a working Grails development environment setup. In this post we are going to go ahead and create our first working application using the framework.

For the first application, we're going to be creating a very simple application called BookStore. It's going to consist of only two types of "objects", called "Book" and "Author". So, to begin with, the first command we want to run is:

grails create-app BookStore

This will go ahead and create the project as well as producing a lot of output. The output is the result of Grails creating the default project directory structure. Being a COC framework, grails assumes certain things about how we're going to layout our project, meaning that the unit tests are under BookStore/test/unit, the integration tests are under BookStore/test/integration and the CSS files are under BookStore/web-app/css.

Next we need to change into the newly created project directory and create the Book domain class:

cd BookStore
grails create-domain-class bookstore.Book


The "create-domain-class" command has gone and created two new files for our project, one to define our Book class and the other a Unit test class for Book. They can be found under:

BookStore/grails-app/domain/bookstore/Book.groovy
BookStore/grails-app/test/unit/bookstore/Book.groovy


In order to do something a little more useful with our domain class, we're going to have to give it "properties". In order to do this, open the domain class definition for Book and modify it to look like the following:

package bookstore
class Book {

String title
Author author
static constraints = {
}
}


We now have a Book class with a "name" and an "author" property. However, we haven't created the Author class yet, so this property isn't pointing to anything at the moment. Let's change that by creating an Author class:

grails create-domain-class bookstore.Author

This should create the Author domain class in much the same way that it created the Book class. Let's modify this new class to have a name property and let's add a property to point to all of the books that this author has written. Modify the BookStore/grails-app/domain/bookstore/Author.groovy file to look like the following:

package bookstore
class Author {
String name
static hasMany = [books:Book]
static constraints = {
}
}


The line static hasMany = [books:Book] is an important one as it defines the "many" part of the "one-to-many" relationship between Book and Author. i.e. each Book has one Author and an Author can have many Books.

We can now run our application with:

grails run-app

And then navigating to http://localhost:8080/BookStore/. However, at the moment this just shows us the default grails home page and there's not much we can do with it. This is because we haven't defined any controllers in our application. Controllers, of MVC fame, are the things which handle the application logic of our web-app. What does this actually mean? Well, they receive incoming requests, decide where to send them and how to deal with any incoming data. They also supply data to the view layer to be used to display our objects to the user.

In order to grace our application with some controllers and views, we will execute the generate-all command which will get us up and running with both a controller and views:

grails generate-all bookstore.Book

We then also need to do this for the Author class:

grails generate-all bookstore.Author

Now, when we run the grails run-app command and navigate to http://localhost:8080/BookStore we should see two controllers on the default Grails page. Selecting either of these controllers will allow us to execute the full set of CRUD commands on the Book and Author classes.

If you've had a go at creating a new Author and/or Book object(s) you'll notice that when creating a new Book for example there is an Author drop down generated containing a list of all of the Authors. However, instead of displaying the Author's name property, the drop down is listing the id and the class type, which is not very pretty. To change this behaviour we're going to overwrite the toString method for both the Book and Author class.

Modify Book.groovy to look like:

package bookstore
class Book {

String title
Author author
static constraints = {
}
String toString(){ return title }
}


And Author.groovy to look like:

package bookstore
class Author {
String name
static hasMany = [books:Book]
static constraints = {
}
String toString(){ return name }
}


And that's it for now. We've ended up creating a simple BookStore application with two domain objects in a one-to-many relationship.

I've only started scratching the surface of what can be done with Grails. In the coming weeks I'd like to go over unit tests, views, authentication and authorization and as many more topics as time will allow.

No comments: