GORM constraints: validator for boolean fields - validation

I'm trying to set a simple restriction on the field of the domain object using the closure in constraints but it does not work.
For example, I have three fields:
boolean organization1 = false
boolean organization2 = false
boolean organization3 = false
organization3 field can be set only if organization1 field is set:
class Organization {
boolean organization1 = false
boolean organization2 = false
boolean organization3 = false
static constraints = {
organization1()
organization2()
organization3(validator:{organization3, organization -> return organization.organization1 ? true : false })
}
}
Controller actions and GSP- views I get by using scaffolding. That's what happens:
How to properly set a restriction? I would be very grateful for the information. Thanks to all.

Not sure if I got it correctly, but I'd put the validator this way:
static constraints = {
organization3 validator:{ org3, org -> !org3 || org3 && org.organization1 }
}

Related

How to reference different fields in Grails custom validator

I am trying to simply reference a different domain field(benefiaryname) from a transient field validator. How to accomplish this?
class Fytrnlt {
transient Boolean firevalidation = false
String checknum
String bankcode
String branchcode
String benefiaryname
............
firevalidation validator: {inputValue, obj ->
// def CheckResult = obj.bannerService.documentValidation(inputValue, benefiaryname, null)
def CheckResult = obj.bannerService.documentValidation(inputValue, {benefiaryname}, null)
if (CheckResult != 1)
return false
} */
Inside your validator function the obj variable is the current object, so, you should be able to simply reference obj.beneficiaryname.

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.

Grails default nullable constraints

In my Grails app I have the following command object
#Validateable
class CalendarEventCommand {
#BindingFormat('FestivalType')
Collection<FestivalType> types
Date start
Date end
MapFocalPoint location
boolean freeOnly = false
}
which is used as the argument to a controller action
def getCalendarEvents(CalendarEventCommand calendarEventCommand) {
if (calendarEventCommand.validate()) {
log.error "Command errors $calendarEventCommand.errors"
} else {
log.warn "Everything is fine"
}
}
In Config.groovy I've specified the following as the default constraints
grails.gorm.default.constraints = {
// apply a max size of 191 chars to String columns to support utf8mb4
// http://mathiasbynens.be/notes/mysql-utf8mb4
'*'(maxSize: 191)
// this shared constraint provides a way to override the default above for long text properties
unlimitedSize(maxSize: Integer.MAX_VALUE)
}
If an instance is created with a null value for start and end validation passes, but I wouldn't expect it to because AFAIK a default constraint of nullable: false should be applied to all properties. I've tried adding this explicitly, by changing the first default constraint to
'*'(maxSize: 191, nullable: false)
But validate() still returns true when start and/or end are null. If I add these constraints to CalendarEventCommand
static constraints = {
start nullable: false
end nullable: false
}
then validate() returns false, but AFAIK it shouldn't be necessary for me to add these constraints.
I think this is an expected behavior. There are couple of JIRA defects regarding this functionality out of which GRAILS-7431 and GRAILS-8583 seems more focused towards the behavior.
I was going through DefaultConstraintEvaluator.java which takes care of global constraints only for domain classes. I think we have to end up using the way mentioned later.
static constraints = {
start nullable: false
end nullable: false
}

Grails command object binding if it doesn't satisfy constraints

Can I bind default field if it doesn't satisfy constraints? Suppose I have
class MyCommand {
String tag = "defaultTag"
static constraints = {
tag inList: ['a', 'b']
}
}
When users passes ?tag=myHackieTag I don't wanna check is command object valid - just use default value (defaultTag)
You could create your own set of getter setter methods for this, no?
class MyCommand {
String tagValue
void setTag( value ){
tagValue = value in ['a', 'b' ] ? value : 'defaultTag'
}
String getTag(){
tagValue
}
}
Not sure how this works with the new bindable stuff in grails 2.
you can validate a single parameter, e.g.
if (!myCommand.validate(['tag'])) {
// provide your default value when validation fails
myCommand.tag = "defaultTag"
}

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

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!

Resources