Ben Klein
Ben Klein

Reputation: 1949

Why does Grails ignore this particular String parameter unless I bind it explicitly?

I have a class Item:

class Item {
  String title
  String description
  String linkText
  String linkUrl

  static constraints = {
    title blank: false
    description blank: false
    linkText blank: false
    linkUrl blank: false, url: true
}

and when I attempt to save a new instance of Item using

def itemInstance = new Item(params)
itemInstance.save()

I get a validation error:

Property [linkText] of class [class Item] cannot be null

I have two problems with this:

  1. linkText is right there in the form, in a <g:textField> with name="linkText". Why is it not being bound to itemInstance? If I print out the params before a save(), I get them all, including linkText, but if I then print out the properties of the pre-saved itemInstance when I have constructed it from those params, linkText on the instance is null. I can change my saving code to

    def itemInstance = new Item(params)
    itemInstance.linkText = params.linkText
    

    and it will be saved without any problems and use params.linkText. But why should I have to do that? Is linkText a reserved keyword or something now? (All I know is that it wasn’t in 2008.)

  2. Why am I getting a “nullable” error rather than one for “blank”? They are different errors. I have a custom message in messages.properties for this, but even given that Grails does not want to use that right now, I would expect it to be giving me its default.blank.message (“Property [{0}] of class [{1}] cannot be blank”).

No. 1 on that list is the most concerning to me, but I really don’t see why Grails is treating this field any differently from all of the other three Strings in the class in the first place.

Upvotes: 4

Views: 352

Answers (2)

uchamp
uchamp

Reputation: 2512

As mentioned in the comment, I tried this in a fresh project and could not reproduce the issue.

For #1: I would try a couple different things:

  1. A new map with all key/value pairs (not a clone of params) and try instantiating my Item using this custom map. Just to confirm if it's the domain/constraints or the params map that is causing the unexpected behaviour.
  2. A clone of params and then use it for instantiating.

If it works fine in both the cases then I'd take a very close look on my actual params map and compare it with the working clone.

Upvotes: 1

c_maker
c_maker

Reputation: 19996

I believe #2 is happening because:

  • "By default, all domain class properties are not nullable (i.e. they have an implicit nullable: false constraint)." (Quoted from Grails Validation documentation).
  • I suspect that in the order of validation, grails checks the nullability constraint first for attributes. (Need to verify this, however)

I suspect these are the reasons why you are getting the null constraint and not the blank one. I believe that if you set the linkText property to be nullable: true, then you would start getting the error message for the blank constraint. Now I tried this and it is not behaving how I expect it to.

For the following domain class:

class Item {
  String linkText

  static constraints = {
    linkText nullable: true, blank: false
}

And attempting to save it like so:

def item= new Item(linkText: "")
item.save()

Grails is happily saving the item with a blank value. However, if I take out the nullable: true constraint, it complains about the blank value.

Upvotes: 1

Related Questions