In a Grails domain object, is it possible to validate a field based on another field? - validation

I have a Grails domain object that looks like this:
class Product {
Boolean isDiscounted = false
Integer discountPercent = 0
static constraints = {
isDiscounted(nullable: false)
discountPercent(range:0..99)
}
I'd like to add a validator to discountPercent that will only validate if isDiscounted is true, something like this:
validator: { val, thisProduct ->
if (thisProduct.isDiscounted) {
// need to run the default validator here
thisProduct.discountPercent.validate() // not actual working code
} else {
thisProduct.discountPercent = null // reset discount percent
}
Does anyone know how I can do this?

This is more or less what you need (on the discountPercent field):
validator: { val, thisProduct ->
if (thisProduct.isDiscounted)
if (val < 0) {
return 'range.toosmall' //default code for this range constraint error
}
if (99 < val) {
return 'range.toobig' //default code for this range constraint error
} else {
return 'invalid.dependency'
}
You can't both have a special validator that relies on something else and have a special validator, as you can't run a single validator on a field (that I know of), only on single properties. But if you run a validation on this property, you'll depend on yourself and go into endless recursion. Therefore I added the range check manually. In your i18n files you can set up something like full.packet.path.FullClassName.invalid.dependency=Product not discounted.
Good luck!

Related

Validate nested domain class instance in command object

I try to validate a nested domain class instance on a command object.
Having the following command object
package demo
import grails.databinding.BindingFormat
class SaveEventCommand {
#BindingFormat('yyyy-MM-dd')
Date date
Refreshment refreshment
static constraints = {
date validator: { date -> date > new Date() + 3}
refreshment nullable: true
}
}
And having the following domain class with its own constraints
package demo
class Refreshment {
String food
String drink
Integer quantity
static constraints = {
food inList: ['food1', 'food2', 'food3']
drink nullable: true, inList: ['drink1', 'drink2', 'drink3']
quantity: min: 1
}
}
I need when refreshment is not nullable the command object validates the date property and check the corresponding restrictions in refreshment instance
For now try with this code in the controller:
def save(SaveEventCommand command) {
if (command.hasErrors() || !command.refreshment.validate()) {
respond ([errors: command.errors], view: 'create')
return
}
// Store logic goes here
}
Here through !command.refreshment.validate() I try to validate the refresh instance but I get the result that there are no errors, even when passing data that is not correct.
Thank you any guide and thank you for your time
I typically just include some code that will use a custom validator to kick off validation for any property that is composed of another command object. For example:
thePropertyInQuestion(nullable: true, validator: {val, obj, err ->
if (val == null) return
if (!val.validate()) {
val.errors.allErrors.each { e ->
err.rejectValue(
"thePropertyInQuestion.${e.arguments[0]}",
"${e.objectName}.${e.arguments[0]}.${e.code}",
e.arguments,
"${e.objectName}.${e.arguments[0]}.${e.code}"
)
}
}
})
This way it's pretty clear that I want validation to occur. Plus it moves all the errors up into the root errors collection which makes things super easy for me.
Two things I could think of:
Implement grails.validation.Validateable on your command object
What happens when you provide an invalid date? Can you see errors while validating?

Grails validation on an associated 'hasMany' object

I'm having a validation issue very similar to what is described here
https://schneide.wordpress.com/2010/09/20/gorm-gotchas-validation-and-hasmany/
but with an important difference that I don't have (or want) a List<Element> elements field in my domain. My code is
class Location {
static hasMany = [pocs: LocationPoc]
Integer id
String address
String city
State state
String zip
...
static mapping = {
...
}
static constraints = {
def regEx = new RegEx()
address blank: true, nullable: true, matches: regEx.VALID_ADDRESS_REGEX
city blank: true, nullable: true
state blank: true, nullable: true
zip blank: true, nullable: true
...
}
}
however, if I save/update a location with a bunk POC (point of contact), I get some wild errors. I would like to validate the POC's when I save/update a location, but I'm not exactly sure how. I've tried a few variations of
pocs validator: {
obj -> obj?.pocs?.each {
if (!it.validate()) {
return false
}
}
return true
}
to no avail. Is this possbile without creating a new field on my domain, List<LocationPoc> pocs?
You're close. The issue is you need to target the property you want to validate instead of using the object reference. It should look like this:
pocs validator: { val, obj, err ->
val?.each {
if (!it.validate()) return false
}
}
Validation doesn't automatically cascade through hasMany associations. In order to get free validation, the other side of the relationship needs to belong to Location.
You didn't include your LocationPOC class, but if you modify
Location location
to
static belongsTo = [location: Location]
Then you will get cascading validation when you save your Location object.
If you can't set the belongsTo property on LocationPoc, and need to use the custom validator, the syntax is a bit different than the answer above.
pocs validator: {val, obj ->
val?.inject true, {acc,item -> acc && item.validate()}
}
the three arguement version of validate expects you to add errors to the errorCollection. https://grails.github.io/grails2-doc/2.5.6/ref/Constraints/validator.html
Plus using a return statement inside of .each doesn't work like the above example. It just exits the closure and starts the next iteration. The validator from the other answer was just returning val (the result of val.each is just val)
You need to spin through the entire collection looking for non valid options.

How can i place validations for fields in groovy for specific format

I have Domain class and in that for a particular field of type String, it accepts alphanumeric values,i need a validation in the format it should accept only AB12-QW-1 (or) XY-12 values. how can i validate the field.
Please suggest the solution.
Thanks.
Assume your domain class looks like this
class Foo {
String bar
}
If you can define a regex that matches only the legal values, you can apply the constraint using:
class Foo {
String bar
constraints = {
bar(matches:"PUT-YOUR-REGEX-HERE")
}
}
Alternatively, if you can easily list all the legal values, you can use:
class Foo {
String bar
constraints = {
bar(inList:['AB12-QW-1', 'XY-12'])
}
}
If neither of these solutions will work, then you'll likely need to write a custom validator method
You could use a custom validator:
class YourDomain {
String code
static constraints = {
code( validator: {
if( !( it in [ 'AB12-QW-1', 'XY-12' ] ) ) return ['invalid.code']
})
}
}
However, your explanation of what codes are valid is a bit vague, so you probably want something else in place of the in call
[edit]
Assuming your two strings just showed placeholders for letters or numbers, the following regexp validator should work:
constraints = {
code( matches:'[A-Z]{2}[0-9]{2}-[A-Z]{2}-[0-9]|[A-Z]{2}-[0-9]{2}' )
}
And that will return the error yourDomain.code.matches.invalid if it fails

How to ensure a boolean field to be set in Grails?

I want to ensure that one of two form fields representing a boolean value is checked. But there is no appropriate constraint to do this. nullable: false does not work.
class Organisation {
Boolean selfInspecting
static constraints = {
selfInspecting(nullable: false)
}
}
How can I check whether one of the two fields is checked or not?
Perhaps the simplest approach is to use a form that ensures a value is picked. As such, creating a radio buttons rather than checkboxes is a better solution. It would directly represent your intent as well.
You can also check this in the Controller, e.g.
if (params.checkBox1 != 'on' && params.checkBox2 != 'on')
flash.error = 'At least one value must be checked.'
return ...
you can write your own custom validator.
something like
selfInspecting(validator: {val, obj -> /*test selfInspecting here*/})
EDIT -- in response to the other answer -- you can handle this on the form, but you should also handle it on the server.
ANOTHER EDIT -- It was suggested in a comment that you might want to validate one of two fields on your Domain class. This is also easily accomplished with a custom validator. With the signature above for the custom validator closure, the val is the value selfInspecting, and obj is the domain object instance. So you could have
{ val, obj ->
if (val == null) return false // if you want to ensure selfInspecting is not null
else return true
... or ...
// if you want to check that at least 1 of two fields is not null
def oneOrTheOther = false
if (obj.field1 != null || obj.field2 != null)
oneOrTheOther = true
return oneOrTheOther
}

Custom Grails validation

I would like to check to make sure two fields are not equal and one is greater then the other. Say yearBorn and yearMarried. They cannot be equal and yearMarried must be greater then yearBorn.
You can use a 2-parameter custom validator that has access to both the value being validated and the entire instance:
static constraints = {
yearMarried validator: { year, instance ->
if (year == instance.yearBorn) {
return 'i18n.code.for.equal.value'
}
if (year <= instance.yearBorn) {
return 'i18n.code.for.born.after.married'
}
}
}

Resources