Fork me on GitHub

25 Feb 2010

Using a custom data binder with Grails domain objects

Yesterday I read a post by Stefan Armbruster on how to register a custom data binder to lookup Grails domain objects by any arbitrary property. I wanted to go a little further so that I could not only bind existing domain instances but create new ones as well.

For example, let's say I have Artist and Album domain classes where Artist hasMany Albums and Album belongsTo Artist. Artist has a name property that is unique. On my create album page I want to be able to type in the artist name and have the save action in the controller automatically lookup an existing Artist instance or create a new one if it doesn't exist. Doing this I don't want to have to add or change anything in the save action itself - I could theoretically use dynamic scaffolding.

Adapting Stefan's PropertyEditor implementation I created this:
The crucial change is the if (!value) block which creates the new instance and populates the relevant property.

To make everything work I just need to:
  1. Add the PropertyEditorRegistrar and place it in resources.groovy as per Stefan's post.
  2. Have a text input or autocompleter with the name "artist" in my create album form.
  3. Add artist cascade: "save-update" to the mapping block in Album so that when the Album is saved the new Album will get saved as well.

6 comments:

Anonymous said...

Returning a new instance in case that an object is not found is definitely a good point.

Unknown said...
This comment has been removed by the author.
Unknown said...

thank you very much, this is exactly what I needed for my Country table ^^

Anonymous said...

Using the ?: operator, there a more groovy way to implement setAsText as a one-liner:

void setAsText(String text) {
domainClass."findBy${StringUtils.capitalize(property)}"(text) ?: domainClass.newInstance((property): text)

}

Jérémy MARC said...

I am trying to use the same code but I have an StackOverflowError in the line :
propertyEditorRegistry.registerCustomEditor(Account, new DomainClassLookupPropertyEditor(domainClass: Account, property: "name"))

Dont know why

michaelvk said...
This comment has been removed by the author.