More image uploading: ImageTools, Transients and Grails

Something that I have come across in my experimentation with Grails is the need to have UI elements in the screen that map to more complex elements in the domain model or things that are not stored in the database. I really like the automagic generation of view elements in Grails GSP files, and have used transient properties to generate views that allow for uploading files. In this post, I will discuss how I used the transient property to enable image uploading in Grails.

One of the ways in which transient properties can be used is to generate the file upload components within the GSP needed to do file uploading. For one of my projects, I needed to allow users to upload an image that I would then save to disk and display. I took a look at the file upload abilities in Grails and liked it, but wasn’t too convinced this would be the most elegant way to go. I didn’t like the manual adding of the form objects in the CRUD generated GSPs since I would often overwrite the generated ones by accident.

The application I am building is basically a series of recipes with a picture that went with each. The image needed to be scaled to one size, and saved to a specific directory.

The solution I came up with involved using the Transient property within my Recipe class, so my domain class looks something like this:

class Recipe {
byte[] image
String imageURL
static transients = [“image”]
}

When I generated the views, the byte[] image will ensure that the image button gets generated into a file browser. In my update and save methods of the controller, I call this

if( recipe.image != null)
recipe = updateImage( recipe )

I use the imageTools plugin in grails to resize my images, and define two new properties in my conf/Config.groovy to set the thumbnail size and download directory.

I defined a new method called image upload:

def updateImage( Recipe recipe ){

// define image tools component
def imageTool = new ImageTool()

// load uploaded byte array
imageTool.load(recipe.image)

// resize image
imageTool.thumbnail( grailsApplication.config.imageTools.thumbsize )

// generate a unique save file name
File saveLocation = grailsAttributes.getApplicationContext().getResource( File.separator + grailsApplication.config.imageTools.savelocation ) .getFile()
saveLocation.mkdirs()
File tempfile = File.createTempFile( “recipe”, “.jpg”, saveLocation )

// save resized thumbnail
try{
imageTool.writeResult( tempfile.getAbsolutePath(), “JPEG”)
} catch( Exception e ){
}

// set image url
recipe.imageURL = saveLocation.getName() + “/” + tempfile.getName();
return recipe
}
While this looks like a lot, it is important to note that the Transient property made me not have to deal with the complexity of the multipart request in grails, instead allowing me to access the file by simply calling recipe.image. Since transient properties don’t get saved in the database, it is the perfect solution for those scenarios where you want to allow more functionality within the views that are needed by the model.

16 thoughts on “More image uploading: ImageTools, Transients and Grails

  1. spcmdr

    Hi

    I am trying to upload files using grails.
    Did you have to specify the property action in your form tag ?
    ()
    I notice that with that the controller is not able to handle the to the right closure.

    Thanks

    Reply
  2. tomas Post author

    This should work with the grails generated views, as it simply uses Grails scaffolding to handle the file upload. The trick here is to just attach a byte[] to the field to be uploaded and mark it as transient, since it will allow you to take the file.

    So this is a simple save() call on the edit.gsp view that gets generated.

    Reply
  3. Tomas Lin Post author

    There are no changes to conf-file. The only thing that I added so that it can be overwritten later is the destination directory and image thumb size:

    imageTools.savelocation = “myuploads”
    imageTools.thumbSize = 400

    Reply
  4. Christian Hepworth

    Hi thanks for this post, very useful. I seem to be getting an error around this line:

    File tempfile = File.createTempFile( “employee”, “.jpg”, saveLocation )

    Which reads: java.io.IOException: The filename, directory name, or volume label syntax is incorrect

    In my config file i have added: imageTools.saveLocation = “images”, to match the images folder under web-app in my grails application.

    Do you have any idea what the error might be?

    Reply
  5. Tomas Lin Post author

    it might be that your imageTools.savelocation is not set correctly — in my previous comment, I mistyped savedlocation as savedLocation — also check permissions.

    Reply
  6. Si-mon

    Hi, Thanks for this post.

    I do have a problem, running Grails 1.0.3.

    When you edit and update, is causes a 405, method not allowed message.
    any ideas on that, I have not changed anything in the views.

    Reply
  7. Nate

    Hi

    I’m trying to incorporate this plugin, but when i do the writeResult i catch the exception:
    ava.lang.IllegalArgumentException: operation “Encode” requires 1 source object(s).

    any ideas?

    Thanks for the help

    Reply
      1. Banko

        found the problem. it seems the lines around: File saveLocation .. do not work (with NetBeans?) I hard-coded the path at writeResult and it worked.

  8. anonymous

    Hi, I have a doubt, can I use this uploading as part of another domain class? How can I add the upload action to a class controller already built, in order to use the user id as part of the name of the uploaded file.

    I tried the example and it works perfectly, but if I want to add this functionality to another class it doesn’t work.

    Reply
  9. EdWall

    Hi, I don’t speak english very well, but I’ll try it:

    I have a problem in the line:
    File tempfile = File.createTempFile( “recipe”, “.jpg”, saveLocation )

    ERROR:
    Invalid variable name. Must start with a letter but was: “recipe”.

    Do you help me??

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s