Grails 条件可空验证或具有可空选项的自定义验证器
Posted
技术标签:
【中文标题】Grails 条件可空验证或具有可空选项的自定义验证器【英文标题】:Grails conditional nullable validation or custom validator with nullable option 【发布时间】:2012-06-03 11:02:46 【问题描述】:我有一个表格来创建一个地方。根据国家/地区,省(州、地区)字段是否必填。
当不需要时,我想为空,而不是空字符串。我有使所有空表单字段为空的代码:
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()
现在,在 place 域中,我在该省有一个验证器:
province validator: val, obj -> if (obj.country in obj.requiresRegionCountries() && !obj.province) return [province.required]
有了这条规则,我总是得到“province can't be null”,即使它是否需要。
我认为这是因为可空验证器默认设置为 false。
如果我添加 nullable: true,那么即使需要省份,也会跳过自定义验证器,并且可以使用空省份进行保存(我认为这是因为它被实例化为 null)
现在,我需要以某种方式自定义验证器,并且还需要能够在验证器中指定可空值,如下所示:
province validator: val, obj ->
if (obj.country in obj.requiresRegionCountries() && !obj.province)
nullable: false
return [province.required]
else
nullable: true
如何在 Grails 2.0.3 中实现这一点?
【问题讨论】:
【参考方案1】:经过大量研究和反馈,我发现了 2 个有效的解决方案。一个在控制器中。不要在模型中添加任何验证并从控制器动态添加它们:
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
另一种解决方案是Tri在该线程中提出的解决方案,但将自定义验证器放在可空约束之前(否则将不会为空值调用自定义验证器):
static constraints =
province (validator: val, obj ->
if (obj.country == 'Canada' && !val)
return ['province.required']
, nullable: true)
【讨论】:
【参考方案2】:我无法用您粘贴的代码来判断,但如果您的问题是默认验证不允许省为空,您是否尝试过明确允许省为空?每个字段都允许有多个验证器。因此,回到您的原始代码中,只需指定可为空的验证器即可:
province nullable: true, validator: val, obj ->
if (obj != null && obj.country in obj.requiresRegionCountries() && !obj.province)
return [province.required]
编辑: 在自定义验证器中,可能还需要防止 obj 在 if 条件中为 null。
EDIT2:演示项目显示上述验证在 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']
)
控制器...
class MainController
def index()
def place = new Place(country: 'Canada')
if (!place.validate())
render "need province<br/>" + place.errors
else
render "cool"
所以我的想法是我有一个虚拟控制器,我可以在其中调用索引操作,该操作被硬编码以创建类似于您的示例的 Place 域实例。请注意,我只定义了国家/地区字符串,因此我可以在其上键入我的逻辑以进行自定义验证。创建 Place 实例时我没有定义省份,所以它应该为空。在这种情况下,响应页面将打印以下内容...
输出 sn -p ...
need province
grails.validation.ValidationErrors: 1 .... does not pass custom validation]
如果我从 Place 中删除 nullable: true 约束,那么错误就是预期的 null 值...
输出 sn -p ...
need province
grails.validation.ValidationErrors: 1 .... cannot be null]
【讨论】:
感谢您的回复,但是有问题。如果我设置为可空且 place.province 为空,则完全跳过自定义验证。我希望在某些国家/地区可以为空,但在其他国家/地区不可以。 要明确:如果我没有设置 nullable true 并且字段为 null,则会出现错误“不能为 null”并且我的自定义验证器不会执行。如果我添加 nullable: true 并且值为 null,则验证将通过,我的自定义验证器将不会执行。我想对某些国家/地区为空,而对其他国家/地区不为空。这是我目前的行为无法做到的。 可能是 grails 2.0.3 的错误。我正在运行 2.0.4,它适用于我创建的一个简单演示项目,我将粘贴到上面的答案中,以便您进行比较 这段代码:静态约束 = 省(可为空:true,验证器:val, obj -> if (obj.country == 'Canada' && !val) return ['province.required' ] ) 在 Grails 2.0.3 中,如果 val 为 null,则验证器将通过,并且永远不会调用自定义验证器。但是,我发现,如果您首先放置自定义验证器,然后是可为空的,一切正常以上是关于Grails 条件可空验证或具有可空选项的自定义验证器的主要内容,如果未能解决你的问题,请参考以下文章