Kyle Banks

Checking for Dirty (Updated) Properties on a Grails Domain

Written by @kylewbanks on Apr 3, 2013.

GORM provides Grails developers with plenty of useful hooks, events, methods, and functionality, not the least of which is domain events that inform you when domain objects are being created, updated, and deleted (you can find documentation on these events here). Within these events, a common use-case is to determine if a particular domain property has changed, and to act accordingly.

The best place to check for dirty properties is usually in the beforeUpdate event. The beforeInsert and afterUpdate events may also seem like good choices at first, but they may not be depending on the use-case. Before inserting, all properties are dirty because they are new, so they haven't really changed they have just been created. After updating, none of the properties are dirty because the new values have already been persisted in your database. These events provide plenty of value if used correctly, but may not always be the best place to check for dirty domain properties.

One domain in particular that I always perform dirty property checks on is any User domains that my application requires. For instance, if a User object's password has changed, you may want to be alerted in the beforeUpdate event and encrypt the password before it is inserted into your database.

class User {

    String username
    String password

    ...

    //Called any time the domain is updated
    def beforeUpdate() {

        def dirtyProperties = this.dirtyPropertyNames
        if(dirtyProperties.contains("password")) {
		password = password.encodeAsPassword()
	}

        return true //Indicates that the update can proceed
    }
}

In the case of a User domain, it is also appropriate to use the beforeInsert to perform password encryption.

def beforeInsert() {
    password = password.encodeAsPassword()
}

Note: Be careful not to perform any saves on the domain within these events, as you will get a StackOverflowException. (The event calls .save(), restarting the whole event cycle, where .save() will be called again, and so on. This infinite loop will never end, and the exception will be raised.)

Let me know if this post was helpful on Twitter @kylewbanks or down below!