views:

142

answers:

1

I'm having a hard time figuring this validation problem. I have one parent domain class defined as follows:

class Person {
    String fullName
    List telephones = []

    static hasMany = [telephones : Telephone]

    static constraints = {
        fullName(size:3..50, blank:false, nullable:false)
    }
}

Then a sublcass:

class SalesAdvisor extends Person{
    Float comission //In percentage
    Portfolio customerPortfolio
    Inventory inventory

    static constraints = {
        comission(range:0..100, scale:2, nullable:false)
        customerPortfolio(nullable:false) 
        inventory(nullable:false)
    }
}

In the SalesAdvisorController I save SalesAdvisor instances:

def save = {
    def portfolio = new Portfolio()
    def inventory = new Inventory(name:'${params.fullName}Inventory', description:"${params.fullName}'s Inventory")
    params.customerPortfolio = portfolio
    params.inventory = inventory
    def salesAdvisor = new SalesAdvisor(params)

    if(!salesAdvisor.hasErrors() && salesAdvisor.save()){
        log.info("New instance of SalesAdvisor saved.")
        redirect(action:show, id:salesAdvisor.id)
    }else{
        log.error("There was an error saving the sales advisor.")
        salesAdvisor.errors.allErrors.each{
        println it.code
    }
    render(view:'create', model:[salesAdvisor:SalesAdvisor])
  }
}

In order to display any errors, in the 'create' view I have:

<g:hasErrors bean="${salesAdvisor}">
    <div class="errors">
        <g:renderErrors bean="${salesAdvisor}" as="list" />
    </div>
</g:hasErrors>

Validation seems to be working fine. However if I submit a string instead of a float for the comission field, in logs I can see "typeMismatch" but the view renders nothing! The message.properties file has a default entry for typeMismatch. Same thing for the fullName field, in logs I can see "nullable" and "blank" errors, but the view renders nothing.

I'm guessing it's more the view's fault than the controller or the domain, since unit tests behave like they should.

+1  A: 

I'd say the problem is a simple typo in your model-passing code:

render(view:'create', model:[salesAdvisor:SalesAdvisor])

(note the uppercase SalesAdvisor value). Try

render(view:'create', model:[salesAdvisor:salesAdvisor])

As a side note, there is a bug in your Inventory constructing code:

name:'${params.fullName}Inventory'

You should use double-quotes here (GString).

Daniel Rinser
I'm not at home so I can't try it, but I always thought that when passing a model to the view (via the model map), the key is how the view will access the value, and the value is the domain class? But now I see that the value must be the instance itself.
Cesar
Well, I guess the term "model" is a bit overloaded and thus ambiguous. Usually you refer to the domain model (often backed by a database and an ORM framework) as the model (the "M" in MVC). The map which you pass from a controller action to the view is actually something different. Although it often contains instances of domain model classes, you're not limited to this at all. You can pass any values you want/need to use in your view. In your case, the renderErrors tag expects salesAdvisor (bean="${salesAdvisor}") to be an instance of a domain class (the one that might contain errors).
Daniel Rinser