Search code examples
grailsgrails-orm

Why am I getting this ValidationException in my save method?


I have a CourseOffering domain class which has a property of type Term, which is another domain class.

CourseOffering

class CourseOffering {

    static fetchMode = [term: 'eager']

    String title
    String key 
    Term term
}

Term

class Term {
    String description
    String identifier
    String isCurrent
    Date midterm
}

I have a page to create a new CourseOffering, here is the gsp for that page. Edit: forgot to mention that the variable 'terms' that I am using here is simply a passed in value of Term.list()

<g:form name="myForm">
    <div class="input">
        Course Title <input type="text" name="title">
        <br><br>
        Course Key  <input type="text" name="key"> 
        <br><br>
        Term <select name="term">
                <g:each var="term" in="${terms}">
                    <option value="${term.id}" <g:if test="${term.isCurrent ==  'Y'}">selected</g:if>>${term.description}</option>
                </g:each>
        </select>
        <br><br>
        <g:actionSubmit action="save" value="Create" />
    </div>
</g:form>

Here is the save method in the CourseOfferingController

def save() {
    CourseOffering newCourse = new CourseOffering(params)
    Term term = Term.get(params.term)
    newCourse.term = term
    assert(newCourse.term instanceof Term) // I put this here to make sure it was a Term!

    if (newCourse.save(failOnError: true)) {
        flash.message = [type: 'status', text: "Succesfully added ${newCourse.title} to the list of course offerings."]
    }
    else {
        flash.message = [type: 'errors', text:"Unable to add course to the list of course offerings."]
    }

    redirect(action: 'index')
}

Aaaannnddddd this is what happens when I try to save the newly created CourseOffering

URI: /office/courseOffering/index Class: grails.validation.ValidationException Message: Validation Error(s) occurred during save(): - Field error in object 'mcidc.CourseOffering' on field 'term': rejected value [mcidc.Term : 9618]; codes [typeMismatch.mcidc.CourseOffering.term,typeMismatch.term,typeMismatch.mcidc.Term,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [mcidc.CourseOffering.term,term]; arguments []; default message [term]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'mcidc.Term' for property 'term'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [mcidc.Term] for property 'term': no matching editors or conversion strategy found

Around line 73 of grails-app\controllers\mcidc\CourseOfferingController.groovy 70: newCourse.term = term 71: assert(newCourse.term instanceof Term) 72:
73: if (newCourse.save(failOnError: true)) { 74: flash.message = [type: 'status', text: "Succesfully added ${newCourse.title} to the list of course offerings."] 75: } 76: else {

What's going on here? I proved that newCourse.term is of type Term with my assert statement, so why is it saying that it's a String? I'm so confused.

Sorry for the horrible formatting of that stacktrace but I really battled with the formatting on here and I couldn't figure out how to make it look nice. I tried to just post a picture of it, but I don't have 10 reputation. The exception is happening on newCourse.save(failOnError: true)


Solution

  • The issue is with this line:

    CourseOffering newCourse = new CourseOffering(params)
    

    Because you created the newCourse by passing in the params, you are binding the param 'term' which has no means to convert convert one from a string.

    Renaming the term param to termId and this will move you forward.

    GSP View:

    Term <select name="termId">
                    <g:each var="term" in="${terms}">
                        <option value="${term.id}" <g:if test="${term.isCurrent ==  'Y'}">selected</g:if>>${term.description}</option>
                    </g:each>
            </select>
    

    Controller:

    def save() {
        CourseOffering newCourse = new CourseOffering(params)
        Term term = Term.get(params.termId)
        ...
    }