Grails fileupload without touching the scaffolding actions (kinda)

November 20th, 2009

Well, when I'm prototyping and generally developing with grails I do not want to use generate-all and just edit the generated controllers and gsps. I try to find my way overwriting maybe some actions but not edit them and some or more changes to the scaffold templates.


So after adding the basic domain classes I always end up doing a grails install-templates in order to start playing with the templates. In most cases this works just fine except from one case. File uploading is a little bit tricky. Most times (actually all the times) I wan't the uploaded files to be stored somewhere (not in the database) and just keep a record of the path of the file to the database. Consider something like the domain class below:

class UploadedFile {
  String filepath

The point here is to just use this class for the prototyping and then handle more "exotic" stuff like fileupload. Lets say that the time to handle this exotic stuff has came...

beforeInterceptor to the rescue

Grails has the ability to intercept calls to actions. All we want to do is before an action (save, and update in this case) just do the fileupload and replace the posted parameter with the path in order to be used by the action.

class UploadedFileController {
  def scaffold = true
  def beforeInterceptor = [action:this.&fileupload, only: ['save', 'update']]
  def fileupload() {
    def filepath //the path of the uploaded file
    // handle normal file upload as per grails docs
    params.filepath = filepath

This is it! Isn't it? Well, it isn't! For some reason data Binding does not work witch means that we have to also edit the Controller template in order exclude the filepath and put it manually. So a the save action we replace the def ${propertyName} = new ${className}(params) with:

def ${propertyName} = new ${className}()
bindData(${propertyName}, params, [exclude: 'filepath'])
if (params.filepath) ${propertyName}.filepath = params.filepath

And in the update action replace ${propertyName}.properties = params with

bindData(${propertyName}, params, [exclude: 'filepath'])
if (params.filepath) ${propertyName}.filepath = params.filepath

And if you don't care about deleting the files when a UploadFile domain gets deleted you are done. v3.6.2 © Georgios Valotasios - CSS inspired by Adam Wathan's blog