Grails: Tomcat File Upload Woes
Things aren't always groovy in the Grails world. Grails makes an effort to support many disparate application servers. Sometimes this all encompassing approach can lead to problems. This is a "Grails gotcha" I recently ran into.
I'm currently working on an application that requires users to upload files to the server. Thanks to some good documentation, I was able to get this up and running quite easily, or so I thought.
In my development environment, which by default utilizes Jetty, everthing ran fine. The problem didn't appear until I tested the application on Tomcat 6.0.18 which we'll be using in production. My code was as follows:
<g: id="receiptUpload" controller="expenseReport" action="upload" id="${expenseReportId}" method="post" enctype="multipart/-data">
<table width="100">
<tbody>
<tr>
<td><label>File:</label></td>
<td><input type="file" name="image" class="is_required"/></td>
</tr>
<tr>
<td> </td>
<td class="validFileTypes">
jpeg, bmp, png, pnm, tiff, wbmp
</td>
</tr>
<tr>
<td/>
<td><input type="submit" value="Upload"/>
</td>
</tr>
</tbody>
</table>
</g:>
When the user attempted to upload a file, they were greeted with the following error:
Could not find closure property for URI [/expenseReport/upload/1] for controller [ExpenseReportController]!
Can you spot the cause of the problem? Initially it's not that obvious. When I tried to access the controller directly by typing it in the URL, the controller and the closure seemed to be found. Everything appeared to be coded properly. Hmmm...dilemmas, dilemmas.
I deployed the same application on Glassfish and it worked! Okay, the problem was a Tomcat one, but what was the cause? After some trial and error I found the culprit. Tomcat does not like it when you include the id attribute in the <g:> tag! Notice the url in the error message: "/expenseReport/upload/1". That URL is atted improperly for Tomcat. It should be: "/expenseReport/upload?id=1"
Modifying my to pass the id in as a hidden field did the trick. Here's the correct with modified lines in bold text:
<g: controller="expenseReport" action="upload" method="post" enctype="multipart/-data">
<table width="100">
<tbody>
<tr>
<td><label>File:</label></td>
<td><input type="file" name="image" class="is_required"/></td>
</tr>
<tr>
<td> </td>
<td class="validFileTypes">
jpeg, bmp, png, pnm, tiff, wbmp
<input type="hidden" name="id" value="${expenseReportId}" />
</td>
</tr>
<tr>
<td/>
<td><input type="submit" value="Upload"/>
</td>
</tr>
</tbody>
</table>
</g:>
Tomcat only choked on the id attribute during file uploads. It worked as expected in all other scenarios. In summary, don't use the id attributed in <g:form> tags if you plan on doing any file uploading. It will only get you into trouble.

Good Detective Work