Thursday, January 6, 2011

Story of one Grails plugin

It's been one of those days where I felt like I need to create a spike app just to prove things are simple in Grails. A friend of mine is preparing a presentation about using NOSQL databases in applications and since it's pretty darn simple to use MongoDB in Grails I've decided to put together a sample that will utilize this datastore.

It all started soooo simple...

grails create-app example
grails uninstall-plugin hibernate
grails install-plugin mongodb
grails create-domain-class Person
grails create-controller Person
grails create-controller Home

Then I've edited the domain class to have 2 properties firstName and lastName, added scaffolding to the PersonController... Basically the Grails 101 stuff...
The HomeController was also pretty simple. Just the index action that returned the [ people: Person.list() ] map and the view that rendered a table to present this data...

Then the geek kicked in...


I thought: now wouldn't it be nice to have the table sortable? Well, sortable but the sorting itself should be done using Ajax - now that'd be cool :)

Right tool for the job - jQuery


When I think "Ajax" it's as if I'd be thiking jQuery at the same time. For me there's nothing else. Period :)

To do that I first needed to extract the part that rendered <tbody> to a separate template _rows.gsp. Then another action, rows was needed to return sorted list of rows instead. That was again dead simple with GORM:
render template: 'rows', model: [ 
people: Person.list(sort: params.key, order: params.order)
]

Then the actual client-side jQuery magic happened:
$("th").click(function() {
var key = $(this).attr("column");
var order = $(this).attr("order");
$(this).siblings()
.removeClass("order-desc")
.removeClass("order-asc")
.removeAttr("order");
if (order == "desc") {
$(this).attr("order", "asc")
.removeClass("order-desc")
.addClass("order-asc");
} else {
$(this).attr("order", "desc")
.removeClass("order-asc")
.addClass("order-desc");
}
$(this).parents("table").find("tbody")
.load("${createLink(controller: 'home', action: 'rows')}?order=" +
order + "&key=" + key);
});

It's all basic stuff... Nothing to be proud of...

Geeky thinking part 2


A simple idea to turn the code above into a jQuery plugin turned out to be the hardest part. First of all, authoring jQuery plugin is not as simple as I'd like it to be. I'm more of a "File - new" person than "Google, google, google..." one. So after I've finally found out how to create such a plugin I was pretty much exhausted.
But what if it'd be really simple? Something along the line of "File - new" or (in the case of Grails) "grails create-jquery-plugin my-plugin"???

And so I've created the jquery-plugin-authoring Grails plugin. From now on whenever I see that part of my application just fits like a jQuery plugin I simply create one. The template leads me every step of the way (the initialization, default values for options, a method to override them, a list of possible messages my plugin can respond to).

And life is simple again :)

End result


I love to see my results be better than someone else's. In this case comparing what it takes to do all that in pure Java having to glue together Hibernate in Entity Manager mode to use Hades, wiring it all with spring beans and adding the web application part with Wicket seems like tons of work by comparison. In fact It took me about 4 hours from the very beginning to the point where I've had the plugin released, used and all was nice and dandy. Grails rule!

I wonder how much time it'd take to do the same in Ruby on Rails? If any of you could perform such an experiment and share the result it'd be really great!

2 comments:

Alari.Name said...

I am wondered. How have you made mongodb plugin work in production mode? After the long battle I had a stop with several jira tickets created, while an app still never work in production.
What's the magic you use? :)

Matthias Hryniszak said...

I didn't try it yet in production. I'm waiting for the 1.0 of the plugin to emerge.