views:

1176

answers:

1

I'm trying to get grails to validate the contents of a List of objects, might be easier if I show the code first:

class Item {
  Contact recipient = new Contact()
  List extraRecipients = [] 

  static hasMany = [
          extraRecipients:Contact
  ]

  static constraints = {}

  static embedded = ['recipient']
}

class Contact {
  String name
  String email

  static constraints = {
    name(blank:false)
    email(email:true, blank:false)
  }
}

Basically what i have is a single required Contact ('recipient'), this works just fine:

def i = new Item()
// will be false
assert !i.validate() 
// will contain a error for 'recipient.name' and 'recipient.email'
i.errors

What I'd like also do it validate any of the attached Contact objects in 'extraRecipients' such that:

def i = new Item()
i.recipient = new Contact(name:'a name',email:'[email protected]')

// should be true as all the contact's are valid
assert i.validate() 

i.extraRecipients << new Contact() // empty invalid object

// should now fail validation
assert !i.validate()

Is this possible or do I just have to iterate over the collection in my controller and call validate() on each object in extraRecipients?

+1  A: 

If I'm understanding the question correctly, you want the error to appear on the Item domain object (as an error for the extraRecipients property, instead of letting the cascading save throw a validation error on the individual Contact items in extraRecipients, right?

If so, you can use a custom validator in your Item constraints. Something like this (this hasn't been tested but should be close):

static constraints = {
    extraRecipients( validator: { recipients ->
        recipients.every { it.validate() } 
    } )
}

You can get fancier than that with the error message to potentially denote in the resulting error string which recipient failed, but that's the basic way to do it.

Ted Naleid
thank's I'll have a bash at that later tonight
Gareth Davis
This does actually work and is I think the solution I'm going to use. But having spent a bit of time debugging the GrailsDomainClassValidator it seems it should do this automatcally and doesn't in my case because of a hibernate Proxy class getting in the way.
Gareth Davis