Archive for October, 2010

Multiple select with Grails

Thursday, October 28th, 2010

Again, the usual apologies for neglecting the blog – it seems to be the first casualty when I have lots of other things to do.

Today’s tale of woe (I’m starting to feel like Denis Norden with his clipboard) relates to using the <g:select> tag in Grails, and processing the selected item(s).

In a GSP file, I have:

<g:select optionKey="id" from="${potentialResearchers}" name="add_researcher_id" optionValue="userRealName" multiple="yes" size="10" style="width:200px;"/>

This is based on an older version, which didn’t use multiple selection. This select is for adding researchers to an intervention folder, and it can be a chore to select one researcher, click a button, select another, and so on. So, we want to add a whole bunch in one go.

Well, it quickly became apparent that there was an issue in the controller, where we try to process what comes out of the form. If you select more than one item in the form, a list is passed in the parameters. But, if you select just one item, you don’t get a list – just the item itself. Well, to me, passing a list of one element would seem far more sensible – but no problem, I can turn everything into a list first, and then process it.

So, version one of the addResearcher method in the controller:

def addResearcher = {

// ...
def researcherIDs = params.add_researcher_id as List
def researchersToAdd = researcherIDs.collect { User.get(it) }

//...

This all seemed perfectly reasonable – and it works as long as you have less than ten items in your collection of researchers (or more precisely, all the IDs of the researchers have single digits…). For example, if you select researchers with IDs 1, 4, and 6 – you get a list passed, and¬†researchersToAdd is ['1','4','6']. And if you just select researcher with ID 6, it’s ['6'].

But, when you have a researcher with ID larger than 9, and you just select that one researcher, you get problems. For example, you select researcher #637. The value of params.add_researcher_id is the string “637″ – and “as List” converts Strings into lists of their individual characters (which I hadn’t anticipated). So, researchersToAdd becomes ['6','3','7'], with bad results…

After a bit of searching on the web, I found that someone else had a neat solution, so we now have the second (and hopefully final) version:

def addResearcher = {
//...

def researcherIDs = params.add_researcher_id // might be list or single string
def researcherIDlist = (researcherIDs)?[researcherIDs].flatten():null // now it's a list
def researchersToAdd = researcherIDlist.collect { User.get(it) }

//...

This converts the researcherIDs into a list by the square brackets. Of course, if it was a list to begin with, it will now be a list-of-a-list (e.g. [['1','4','6']] ). So flatten() is used to remove that.

Lesson learned this week: make sure you test with large amounts of data, not just the half dozen sample researchers that you created in the Bootstrap.groovy file. What we do now is make a dump of the actual production database, and copy it over to the development database. It’s a bit of a chore, but well worth it. You really only need to do the dump once – I used the mysqldump command for that. See this article for all you need to know – and I’m sure there are utilities that can be used for other databases or if you don’t like using the command line.

Enhanced by Zemanta