Dealing with reference data…the predominantly static data that populates drop-down lists, and so on…always causes wasted brain cycles: for ease of maintenance, we don’t want the values embedded in the code, but we nonetheless do want it centralized.
The Spring underpinnings of Grails (and the way that Grails ’surfaces’ these underpinnings) can offer one solution and help reserve those brain cycles for more deep thoughts.
Here’s a typical example of reference data; the drop-down select car and things lists in this trivial GSP:
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head><title>Reference Data Demo</title></head>
<body>
<h1>Tell me about yourself</h1>
<table cellpadding="10" cellspacing="2" border="0">
<tr>
<td><label for="car">Select your preferred car:</label>
<td><g:select name="car" optionKey="key" optionValue="value" from="${cars.entrySet()}" />
<tr>
<td><label for="things">Select your preferred things:</label>
<td><g:select name="things" optionKey="key" from="${things.entrySet()}" valueMessagePrefix='things' />
</table>
</body>
</html>
<aside>
Something I learned recently and show above: for HTML: “The TR or table row element requires a start tag, but the end tag can always be left out.” I always assumed that these ‘container’ tags had to have both start and end tags. Be warned, however: although a handy shortcut, this creates a document that will not be legal XHTML [which is always best aimed for]. Thus, this falls into the set of “useful tricks and tips that are best ignored for one’s own sanity.” Other members of the set include PERL, and the tactics that could be used for winning an argument against my wife…
</aside>
The above GSP showed how to use the reference data but how is it declared? I simply declared the following in Grails’ conf/resources.groovy file:
beans = {
cars(java.util.HashMap, [slow: 'Toyota Avalon',
fast: 'Bugatti Veyron'])
}
A more traditional ‘Springy’ approach is also possible via conf/resources.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd"> <util:map id="things"> <entry key="good" value="good"/> <entry key="bad" value="bad" /> </util:map> </beans>
Both configuration options can be (and are, in this example) used together.
In both of the above cases, the data is now centralized and separated from the body of the code. Both Good Things.
The second <g:select> shows how to internationalize this feature.
In this case, the value in the things map is used (in conjunction with the valueMessagePrefix attribute value) as a key into the ‘messages’ resource bundle under grails-app/i18n.
For this example, the bundle contains entries such as:
things.good=My Cat things.bad=The Flu
Sadly, there is a bit of a bug here. It does not currently (Grails 1.2-M1 and below, at least) appear possible to use both valueMessagePrefix and optionValue attributes. In this case I have been been lucky and have been able to get away with omitting the optionValue attribute (but the optionKey attribute is still required):
<g:select name="things" optionKey="key" from="${things.entrySet()}" valueMessagePrefix='things' />
In other situations (with collections of other bean classes), one may not be so lucky.
My AUD$0.02 worth on the bug is attached to: http://jira.codehaus … g/browse/GRAILS-3961.
For completeness (its pretty trivial) here’s the controller code:
class ThingController {
def cars
def things
def index = { redirect(action: view) }
def view = {
[cars: cars, things: things]
}
}
Notice the way the two Reference Data Maps are injected into the controller and then pased into the view as its model…clean and simple.
It is possible to do the same sort of thing with filters. This can be useful for showing build numbers, etc. on page headers/footers.
Here’s what it all looks like pulled together (pretty ordinary, but that isn’t the point):

Now. Stop wasting brain cycles on JNDI entries/Properties files/Database entries/Quartz timers/… and get on with more important things.
