Grails rejectValue - 多次检查导致ob.errors为null

时间:2016-09-21 07:29:23

标签: grails

我的域对象预订有多个允许为空的属性,因为它们将在对象保存到数据库后稍后设置。

myService.action()的一部分:

booking.properties = params    

if (booking.contactFirstname?.length() <= 1) { booking.errors.rejectValue("contactFirstname", "empty") }
if (booking.contactLastname?.length() <= 1) { booking.errors.rejectValue("contactLastname", "empty") }
if (booking.contactPhone?.length() <= 1) { booking.errors.rejectValue("contactPhone", "empty") }
if (booking.contactMobile?.length() <= 1) { booking.errors.rejectValue("contactMobile", "empty") }
if (booking.contactEmail?.length() <= 1) { booking.errors.rejectValue("contactEmail", "empty") }    

if (booking.hasErrors() || ! booking.validate()) { 
    return [success: false, model: booking]
} else {
    booking.save(failOnError: true)
    return [success: true, model: booking]                
}

我的控制器确实:

def result = myService.action(params)
if (result.success) {
    flash.success = message(code: "msg.successfullySaved")
    redirect(action: "registerEventConfirmation", id: result.model.uid, params: [lang: params.lang], mapping: "paginated")   
} else {
    flash.error = message(code: "msg.errorSavingCheckFields")
    render(view: "registerEventStep3", params: [lang: params.lang], model: [booking: result.model])

我正在使用     hasErrors(bean:booking,field:'contactFirstname','has-error')}

标记错误字段。

如果我现在在textfields中提交没有任何值的表单,则所有字段都是红色的,booking.errors有> 0个错误。

如果我使用firstname提交表单后,booking.errors为NULL且没有标记其他字段。

这是一个Bug吗?我和Grails 2.3.6

其他信息

  1. 我访问表单,完全提交
  2. 我看到所有表单字段都是红色的,object.errors有&gt; 0个错误(VALID)
  3. 我在第一个字段中输入一个值,firstname并提交
  4. 我看不到红色的表单字段,object.errors = 0 errors(INVALID)
  5. 我重新提交没有更改的表单
  6. 我看到所有空表单字段为红色,object.errors有&gt; 0错误(VALID)

2 个答案:

答案 0 :(得分:1)

现在我完全理解了这种情况,因为我在睡觉时遇到了困难,我想我会给你一个非常简洁的答案,这样你就可以充分理解并正确使用。

首先,我知道创建一个验证bean听起来会有很多工作,所以让我教你如何相对简单地完成它以及为什么它是我的首选方法。

这是我首选的方法,因为当你这样做时

class MyController {

 def myAction(Mybean bean) {
   // 1. the object allowed into this save action 
   // are all that is available objects withing MyBean. 
   // If it has user define but not telephone. Then
   // if telephone is passed to myAction it will fail and not recognise 
   // field
   // When declaring Date someField or User user then the params now 
   // received as bean this way is now actually properly bound 
   // to the data / domainType declared. 
   // Meaning user will now be actual user or someField actually Date 
  }

现在解释如何最好地解决这个问题。创建bean时,只需将实际域类从域文件夹复制到grails 2中的src/groovy/same/package或grails 3中的src/main/groovy/same/package

将名称/类别或副本从Booking更改为BookingBean,以便它具有不同的名称。

@Validateable添加到grails 2中的实际BookingBean之上,或者将实现添加到主类中,例如grails 3中的Class BookingBean implements Validateable {

现在,由于它被复制,所有对象都是相同的,此时控制器的保存将是

class MyController {

     def myAction(BookingBean bean) {
         Booking booking = new Booking()
         // this will save all properties
         booking.properties = bean
         booking.save()
     }
} 

但是你有一个特殊的情况,你想在主域类中声明一个瞬态字段而不是

class BookingBean {
  def id
  String contactFirstname
  String contactLastname
  boolean secondSave=false

 static constraints = {
     id(nullable: true, bindable: true)
    contactFirstname(nullable:true) //,validator:checkHasValue)
    contactLastname(nullable:true) //,validator:checkHasValue)
    secondSave(nullable:true,validator:checkHasValue))

}

//use the same validator since it is doing identical check

static checkHasValue={value,obj,errors->
    // So if secondSave has a value but contactFirstName 
    // is null then complain about contactFirstName
    // you can see how secondSave gets initialise below
    //typical set this to true when you are about to save on 2nd attempt
    //then when set run validate() which will hit this block below

    // Check all the things you think should have a 
    // value and reject each field that don't
    if (val) {
        if ( !obj.contactFirstname) {
            errors.rejectValue('contactFirstname',"invalid.contactFirstname")
        }
        if ( !obj.contactSecondname) {
            errors.rejectValue('contactSecondname',"invalid.contactSecondname")
        }
        //and so on
    }
}

所以现在在你的控制器中:

class MyController {

     def save1(BookingBean bean) {
         Booking booking = new Booking()
         // this will save all properties
         booking.whatEver = bean.whatEver
         booking.save()


 // you can choose to validate or not here
 // since at this point the secondSave has 
 // not been set therefore validation not called as yet in the bean

     }

//你可能有id,它应该与实际的域类绑定

def save2(BookingBean bean) {

         booking.secondSave=true
         if (!bean.validate()) {
            //this is your errors 
            //bean.errors.allErrors
            return
         }
         //otherwise out of that loop since it hasn't returned
         //manually set each object 
         booking.contactFirstname=bean.contactFirstName
         booking.contactSecondname=bean.contactSecondname
         booking.save()


     }

}

e2a旁注 - 上面应该回答

在创建之前不要验证它。仅在创建对象后验证它,然后添加值。替代方法可能在您作为第二次检查的一部分运行的验证bean中创建一个函数。 This Example bean未经过验证until formatRequest被称为as seen here

答案 1 :(得分:1)

我没有理解你的问题的具体细节,所以在我刚刚开始研究之前,我会给出一些一般的指导。

  1. 不要在validate()之前调用hasErrors()。如果你这样做,Grails不会将你的错误从域限制中移除,你只能使用rejectValue()来自己设置错误。

  2. 小心使用rejectValue()。尝试使用域约束设置所有错误。如果您有复杂的约束,请使用验证器语法,偶尔obj.getPersistentValue()可能是您的朋友。

  3. 如果仍然需要使用rejectValue(),请了解以后对validate()的任何调用都将从头开始并删除先前的错误。我为此写了一个解决方法(放在你的域对象中)虽然我无法向你保证它是100%好的:

  4. def validateWithErrors(def fields = null) { def existingErrors = this.errors def ret = (fields ? this.validate(fields) : this.validate()) existingErrors?.allErrors?.each { error -> this.errors.rejectValue(error.field, error.code) } return (existingErrors?.allErrors ? false : ret) }