Whew, Grails has some gotchas. It is so great for so many reasons. But WOW! There are some time sinks tucked away for you to discover. In the hope of helping others, here is a list of the ones that hit me.

Constraints! HasErrors!

Never, EVER forget to add constraints to your composited domain model at the same time you forget to check hasErrors after save. Grails will not tell you when your domain.save() fails. When in doubt, pass failOnError:true to your save() calls.

Where would this hit you? Most of the time scaffolding takes care of your db operations. But, it happened to me in several places. When I was loading a default set of data in Bootstrap.groovy, I never saw my new objects showing up. The other, more devious situation was when I was using the Nimble plugin and extending the User object Nimble provides with some dependent classes. I kept getting the wicked “hibernate transient – must save” exception.  Lastly, most of the time you are wrapping your CRUD in services, you will need to watch out for this.

Watch That Naming!

Many times I’ll create a class manually in the appropriate bucket for what I want to do. For example, instead of going through grails create-integration-test package.Class, I’ll just go create a new class under $GRAILS_APP/tests/integration/package. I spent a good hour trying to figure out why my integration test was not being run. And then I found it. I named my test ClassNameTest.groovy. When it should be ClassNameTest[s].groovy! Doh!

Grails Interactive

The second you have a few maven dependencies and/or plugin dependencies, it can take grails multiple seconds (On average, 3 for me) just to resolve the dependencies of your app. This is a serious flaw in Ivy (the underlying dependency management grails uses). Unfortunately, this is what we are stuck with. Run grails interactive to speed things up. The JVM starts up and keeps running after each command. (The dependency checks go away, but things are still slow.) Further, regardless of how high you specify max memory, it still fails with out of memory errors every few run-app cycles. There must be a few leaks still laying around.

File Uploads

Something no one tells you and is found no where on the grails.org documentation is how to get the true filename of an uploaded file. If you just do what the docs tell you via:

def uploadedFile = request.getFile("file")
uploadedFile.name

the result is that the filename is “file”. Yes, real fucking useful!

Use, instead:

def uploadedFile = request.getFile("file")
uploadedFile.originalFilename

Leveraging established Java codebase

One of the best aspects of Groovy, in my eyes, is being able to leverage Java. Grails goes further and allows you to specify remote maven artifacts your app depends on. This is great. Until you want to reuse Java domain objects.

You see, GORM doesn’t support mapping both Groovy and Java objects if either of those objects refer to each other. So you can’t have a Groovy domain object extend a Java object. You can’t have a Groovy domain object contain a Java domain object. There is an issue open on this:

http://jira.codehaus.org/browse/GRAILS-4996

I’m bringing this up here because this limitation definitely isn’t documented anywhere. And I didn’t discover it until step 98 out of 100 in integrating my codebases.

Further, I found that GORM errors are a bit limited in some circumstances (this one). If you hit a problem where GORM is throwing a cryptic message, and it is about a object in your hasMany map, try removing the hasMany and adding it as a single relationship. The error message gets much more verbose.

(if hasMany, move it to a single to get a better error message from hibernate)

class Tool {
	//static hasMany = [ widgets : Widget, rocks : com.acme.crud.Rock ]
	static hasMany = [ widgets : Widget ]
	Rock rock
	String name

Never *ever* use reserved variables in UrlMappings.

Wait, there are reserved variable names? Yeah, that’s what I said! Say you have a parameter your controller needs called action. $action actually maps to the function in your controller that will be called. So if you use this, suddenly, no request will get to your controller. (Unless it just so happens the type you enter in the URL exists as a function.) This happens even if you use the extended UrlMapping syntax where you can specify the action you want to use. In my case:

"/download/$id/$version/$preview/$action/$filename" {
			controller = "downloadController"
			action = "index"
			constraints {
				
			}
		}

On no, don’t do that! Change $action to something else instead.

About the Author:

Learned something? Great! Need help on your development project? I'm available for hire:

  • Ruby on Rails
  • iOS Development
  • System Architecture & Performance

Get in touch:

Discussion

  1. Abraham says:

    Nice Post. I am also a grails newbie and this definitely helps. I have bookmarked the page and will be returning for more!! Please do keep posting.

  2. Kalps says:

    Hi !! i am also newbie , i just started grails project , i want to check the error , like user entry . i tried couple of IF ‘s even though its not working for sometimes . do we have any other technique to check the user enter data ???

Leave a Comment