Friday Repost: Easy file uploading in Grails

The Friday Repost series are copies from my earlier writings. Since I don’t want to loose them, and they might prove useful to others, I’m reposting them on this blog.

If you want to upload files with Grails, there are multiple ways of doing so. However, there’s at least one way which makes it really easy do so, while keeping the code as clean as possible. This blog describes the steps to take to get the file upload to work, while maintaining a very clean codebase.

To get started, first create a new Grails application by running the following command:

grails create-app imageupload

After you have created your application, create a new file called ‘UploadImageCommand.groovy’ in the src/groovy/com/example/command directory

The UploadImageCommand.groovy should look like this:

Using commands for all changes in the system is usually a good thing. This prevents any malicious code from entering the system, and also describes the
intent of the system by using sensible naming for the commands, in this case ‘Upload Image’.

Now we need two more things: the persistent object (the Domain Object) and the Controller. Actually, I would recommend using a Service for all state changes
of the system, because of the transactional support in services and for providing a uniform way of state changes. However, that’s beyond the scope of this blog, so we’ll
leave it for later and focus on the image uploading for now!

The domain class

To create the domain class, typing in the following:

grails create-domain-class com.example.domain.Image

This creates an Image.groovy file in the grails-app/domain folder. Open the file, and type in the following contents:

Also, create a controller:

grails create-controller com.example.controller.Image

This creates an ImageController.groovy file in the grails-app/controllers folder. Open the file, and type in the following contents:

Now, all you need is a simple form which will upload your image (or actually any kind of document). The easiest way to do this is create a new file called
upload.gsp and place it in the web-app directory . Make the file look like this:

Now, type grails run-app

And browse to http://localhost:8080/imageupload/upload.gsp. When you upload a file there, you will see the counter increase in the log file. Clean, fast and easy!

Testing Grails controller actions that use bindData method and render validation errors as JSON

Let’s assume that we have a controller action in a grails application that updates a user domain instance. We want name and surname to be updateable but login and password shouldn’t be updateble. To achieve that we will use the controller’s bindData() method with whitelisting. The action will be called using ajax so we also want to render JSON with validation errors in response if there were any. So our controller might look like that:

And the example User class might look like that:

Our next step will be unit testing the action. We want to make sure that only the whitelisted fields are copied from parameters (testUpdate) and also that the validation errors are rendered (testUpdateValidationError):

It turns out that those tests won’t pass. But not because of the fact that we have bugs in the code, it’s just that grails doesn’t do enough magic for our controller action to be unit testable out of the box.

First problem is that the bindData() method is not mocked in ControllerUnitTestCase. Fortunately thanks to this stackoverflow response we know how to easily mock it. To make it reusable let’s create a mixin out of it:

Now all that we have to do to make it work is to apply it on our test class and call the mockBindData() method in the setUp() method.

Second problem is that by default the JSON converter doesn’t know how to convert bean validation errors. But that’s easily fixable as well – all we have to do is register validation error marshaller in the testUpdateValidationError test:

After the aforementioned changes our passing test class should look like that: