Search code examples
grailsgrails-3.0

File uploads not working with default scaffolding in Grails


In Grails 3.1.19 I have created a domain class with the following field

byte[] caCert.

When accessing the generated create action I get a file browsing dialog and upload a file. When clicking create I get caCert is type-mismatched.

Looking at the params object it appears that I am only getting the name of the file which is a string. With the default scaffolding how can I get byte[] fields to actually get the content of the file I uploaded? The create controller code is

def create() {
    respond new TaskUser(params)
}

And the save controller action is

def save(TaskUser taskUser) {
    if (taskUser == null) {
        transactionStatus.setRollbackOnly()
        notFound()
        return
    }

    if (taskUser.hasErrors()) {
        transactionStatus.setRollbackOnly()
        respond taskUser.errors, view:'create'
        return
    }

    taskUser.save flush:true

    request.withFormat {
        form multipartForm {
            flash.message = message(code: 'default.created.message', args: [message(code: 'taskUser.label', default: 'TaskUser'), taskUser.id])
            redirect taskUser
        }
        '*' { respond taskUser, [status: CREATED] }
    }
}

The form part of the create template is below

<div id="create-taskUser" class="content scaffold-create" role="main">
    <h1><g:message code="default.create.label" args="[entityName]" /></h1>
    <g:if test="${flash.message}">
    <div class="message" role="status">${flash.message}</div>
    </g:if>
    <g:hasErrors bean="${this.taskUser}">
    <ul class="errors" role="alert">
        <g:eachError bean="${this.taskUser}" var="error">
        <li <g:if test="${error in org.springframework.validation.FieldError}">data-field-id="${error.field}"</g:if>><g:message error="${error}"/></li>
        </g:eachError>
    </ul>
    </g:hasErrors>
    <g:form action="save">
        <fieldset class="form">
            <f:all bean="taskUser"/>
        </fieldset>
        <fieldset class="buttons">
            <g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" />
        </fieldset>
    </g:form>
</div>

Solution

  • I hope this adds some value.

    Been struggling with the same problem here. Created a basic Domain class with an attribute of type byte[] and run the default scaffolding.

    Obtaining the "type-mismatched" validation message when trying to save the instance.

    Based on Gorille's answer I checked the documentation and adding the attribute enctype="multipart/form-data" to the g:form tag would make it works. Not really sure why the scaffolding does not handle that.

    <g:form action="save" enctype="multipart/form-data">
    

    Other option, as he mentioned, is to change the tag to g:uploadForm, which looks is specifically for that.

    Doc:

    The uploadForm tag conveniently adds the enctype="multipart/form-data" attribute to the standard tag.

    Tag doc:

    uploadForm: Identical to the standard form tag except that it sets the enctype attribute to "multipart/form-data" automatically.

    I have checked params and it has the complete file.