Grails Independent Conditional Validation or Custom Validator with nullable Option

I have a form for creating a place. Depending on the country, the province field (state, region) is required or not.

When not required, I want to be empty, not empty. I have code that makes all empty form fields null:

def newparams = [:] place = new Place() params.each() { k, v -> if (v instanceof String && place.hasProperty(k)) { if (!v.trim().length()) { newparams[k] = null } else { newparams[k] = v } } } place = new Place(newparams) place.validate() 

Now, in the domain domain, I have a validator in the province:

 province validator: {val, obj -> if (obj.country in obj.requiresRegionCountries() && !obj.province) return [province.required]} 

With this rule, I always get "the province cannot be zero", even if it is required or not.

I think this is because the nullable validator, which is set to false by default.

If I add a nullable: true value, then even if a province is required, the custom validator is skipped and it can be saved with an empty province (I think this is because it is created using null)

Now I need to somehow configure my validator and also indicate the nullable value in my validator, something like this:

 province validator: {val, obj -> if (obj.country in obj.requiresRegionCountries() && !obj.province) { nullable: false return [province.required] } else { nullable: true } } 

How can I achieve this in Grails 2.0.3?

+6
source share
2 answers

I can’t tell using the code you inserted, but if your problem is that the default check does not allow the province to be null, have you tried explicitly allowing the provinces to be null? Multiple validators are allowed for each field. So, go back to your source code, just specify a null validator:

 province nullable: true, validator: {val, obj -> if (obj != null && obj.country in obj.requiresRegionCountries() && !obj.province) return [province.required] } 

EDIT: A custom validator may also require protection against obj equal to null in the if condition.

EDIT2: A demo project showing the above test doing work on grails 2.0.4

 class Place { String country Province province static constraints = { province (nullable: true, validator: {val, obj -> if (obj.country == 'Canada' && !val) return ['province.required'] }) } } 

controller...

  class MainController { def index() { def place = new Place(country: 'Canada') if (!place.validate()) { render "need province<br/>" + place.errors } else { render "cool" } 

So the idea is that I have a dummy controller where I can trigger an index action that is hard-coded to create an instance of the Place domain, similar to your example. Notice that I only defined the country string, so I can point my logic to this for user verification. I did not define the province when creating the Place instance, so it should be null. In this case, the following will be printed on the answer page ...

The output fragment ...

 need province grails.validation.ValidationErrors: 1 .... does not pass custom validation] 

If I remove the nullable: true constraint from Place, then the error will be a null value as expected ...

The output fragment ...

 need province grails.validation.ValidationErrors: 1 .... cannot be null] 
+5
source

After numerous studies and reviews, I found 2 solutions that work. One of them is in the controller. Do not add validation to the model and dynamically add it from the controller:

 class PlacesController { def create() { def place = new Place(params.address) if (place.country in placesThatRequiresProvinceArray) { place.constrains.province.nullable = false } else { place.constrains.province.nullable = true } 

}

Another solution is the proposal proposed by Tri in this thread, but put the custom validator to the limit with the NULL capability (otherwise the custom validator will not be called for null values):

 static constraints = { province (validator: {val, obj -> if (obj.country == 'Canada' && !val) return ['province.required'] }, nullable: true) } 
+12
source

Source: https://habr.com/ru/post/916888/


All Articles