parameterized Grails validation messages - grails

In the messages.properties file in a Grails application I've seen examples of validation messages such as:
User.password.size=Size of bar must be between {0} and {1}
which applies to
class User {
String password
static constraints = {
password(size:5..15)
}
}
This example assumes that {0} is bound to the minimum size and {1} is bound to the maximum size, but I cannot find any documentation of which parameters may be used by error messages for each built-in constraint. In other words, what I'd like to know is: for each built-in constraint what is the meaning of {0}....{n}

I did some experimentation and I discovered that for a constraint such as:
class User {
String password
static constraints = {
password(size:5..15)
}
}
The values of the placeholders are:
0. Name of the class (User)
1. Name of the property (password)
2. Value of the property
3. First constraint parameter (5)
4. Second constraint parameter (15)
5. etc.

You're right, I've never found any documentation of that either. Best bet? Change your messages to something like:
User.password.size=0:{0}, 1:{1}, 2:{2}, etc...
and see what you get for each one you're interested in. If you posted that info to the Nabble message board on Grails, I'm sure it would find it's way into the documentation.
Good luck.

Related

Grails domain custom error messages

I am working in a grails application, I have many domains in the applications, more than 50! The error message generated are default, I have the following in my message.properties file
default.blank.message=Field "{0}" cannot be blank.
An example of my one of the domain class is as follows:
class Person {
String firstName;
String lastName;
String middleName;
Date dob;
String gender;
String religion;
String nationality;
String maritalStatus;
Zone permAddZone;
District permAddDistrict;
String permAddVDC;
}
And so on, so when I leave a field, for example 'maritalStatus' the following error message shows up, 'Field "maritialStatus" cannot be blank.'. I also added the following to my message.properties file
person.maritialStatus=Maritial Status
But still I am getting the 'Field "maritialStatus" cannot be blank.' message. I also tried using I18n Templates Plugin, but as I have a lot of domain classes, modifying error message for all of them would be time consuming. So, what choices do I have or what am I doing wrong. Any help is appreciated.
The appropriate message key to override is specified on the reference page for each constraint type. In the case of blank it's
com.example.Person.maritalStatus.blank=Marital status must not be blank
However this will be very time consuming and repetitive if you have many domains and many properties.
What you are asking for is instead a way to process the domain class property names in some way before they are inserted into the default messages. This isn't something Grails supports out of the box but I like a challenge... and I've found a surprisingly elegant way to implement it. My approach is the grails plugin available at https://github.com/ianroberts/recursive-messages and it works by extending the format string syntax to support placeholders of the form
default.blank.message=Field "{0,message,field.name.}" cannot be blank.
A placeholder {N,message,prefix} is resolved by prepending the given prefix to the usual placeholder replacement value and then treating the resulting string (field.name.maritalStatus in this example) as a no-argument message key, and looking that up in the usual way. Thus you could have different representations for different languages.
It has to be a plugin because it relies on a trick that works in a plugin's doWithSpring but doesn't work in an application's resources.groovy, to modify the definition of the default messageSource Spring bean.
Disclaimer: this was a quick fix, it hasn't been fully tested and could probably be implemented more efficiently.
In order to override the field label you need to override the key:
<package>.<domainclass>.<fieldname>.label
So in your case, try:
<package>.Person.martialStatus.label=Label

GORM mapping: make an index unique

I'm feeling a little slow today. I'm trying to do something that I think is very simple. I have a Domain class with a property called 'name'. I want 'name' to have an index, and I want the index to require that the 'name' is unique. I've set the unique constraint and tried creating an index. I can't make sense out of the Gorm docs as to how I add the unique attribute to the index. Here's some code:
class Project {
String name
static hasMany = [things:Things]
static mapping = {
name index:'name_idx'
}
static constraints = {
name(unique:true)
}
}
All is well with the above, except when do "show indexes from project" in mysql it shows my name key as not unique. I know the problem is that I am not specifying unique in the mapping, but quite frankly the docs for gorm are making my head hurt. I see all kinds of stuff about columns, but I can't find a single example anywhere on the web that shows what I want to do. I don't need complex mappings or compound keys, I just want to know the syntax to add the unique attribute to the mapping declaration above. Any advice welcome.
I also did a grails export-schema and see the following:
create index name_idx on project (name);
Nothing in that to indicate this index requires unique values
A related followup question would be once I succeed in making that index unique, what type of error should I expect when I go to save a Project instance and the name is not unique? Is there a specific exception thrown? I realize that even if I check that a given 'name' is unique there's still a possibility that by the time I save it there may be a row with that name.
I'm quite sure the syntax to do what I want is simple but I just can't find a simple example to educate myself with. I've been to this page but it doesn't explain HOW the uniqueness is enforced. I'd like to enforce it at the name index level.
The indexColumn allows additional options to be configured. This may be what you're looking for.
static mapping = {
name indexColumn:[name:'name_idx', unique:true]
}
Grails Documentation for indexColumn
If you put only the unique constraint the GORM send DDL to create an unique index on database.
static constraints = {
name nullable: false, unique: true
}

Language-specific value in grails inList constraint

Users of my application have the possibility of choosing some values from list. The values for that list are in simple domain class, Foo, which looks like that:
class Foo{
String name
static mapping = {
id name: 'name', generator: 'assigned'
version: false
}
}
Foo looks the same for every language my app uses. In another class I have a constraint saying that Bar must be in list of Foo. Sometimes user doesn't know what to choose, so he may choose something like "I'm not sure" (so this option should be in list to to meet the inList constraint). Thing is, "I'm not sure" is written differently in different languages. How can I append this value based on current messages to inList constraint?
In your controller you could do:
def theList = foo.list().name // Get any array of strings.
// If you actually need > 1 field then you probably need to
// put the g.message below in a map
theList << g.message(code:"im.not.sure")
I don't believe inList constraint will help you here - it's designed for a simpler use case than yours.
I'd add a method to the class getLanguages() that handles this, and then since you seem to be interested in validation, write a custom validator to make sure right values are saved.

Grails urls mapping

what the urls mapping processing order for the grails framework
"/$object/$id/$collection"
"/$object/$id/bar/list"
"/foo/$id/bar/list"
Which one will execute first. I'm getting unexpected behavior where the generic mapping seems to execute first
what do you want to achieve ?
/$object/$id/bar/list maps /foo/$id/bar/list to.
But if you want any custom behavior for foo you can set constrainst for first mapping, e.g.:
/$object/$id/bar/list {
controller = "bar"
action = "list"
constraints {
object(matches: /.*[^fo].*/)
}
}
"/foo/$id/bar/list"
Regexp is not ideal but it shows basic principles
i believe the order will be
/foo/$id/bar/list // 1 value to calc
/$object/$id/bar/list // 2 value(s) to calc
/$object/$id/$collection // all unknown values
grails documentation states the strongest will take precedent, meaning whatever does not have to be calculated at runtime.

Grails Problem with custom error messages

I am currently trying to specify custom error messages in grails for the default constraints but so far all I get back is the default error message.
I know that I have to edit the grails-app/i18n/messages.properties file
If I change the following default error codes message, it will correctly display the new error message
default.blank.message=Property [{0}] of class [{1}] cannot be blank
However, this is not what I am trying to do. I need more granular error reporting and have more than one field that can be blank etc. What I would like to be able to do would be, display custom messages for each field in a class
package com.mycompany.myapp
class Test{
String name
def constraints = {
name(nullable:false, blank:false)
}
}
(following codes appended to end of messages.properties)
test.name.blank=Name cannot be blank
test.name.nullable=Name cannot be nullable
According to the grails documentation this should work correctly, either with or without the package name - className.propertyName.blank
grails.org/doc/latest/ (constraints section) & (section 7.4 - validation & internationalization)
I have tried all comnbinations that I can think of, but it always displays the custom message
I have also tried installing the grails i18n templates plugin
http://www.grails.org/I18n+Templates+Plugin
which generated the error codes automatically for me. I appended the new error codes to the end of the existing messages.properties file but I still get the default error messages.
However, there was something different with the error codes that were generated by the plugin.
instead of the format specified in the grails doc - test.name.null=......, it automatically generated test.name.null.error=Custom Message
I have also tried deleting the default error messages completely, but they are still displayed
If anyone has experienced this issue before, I would appreciate any help that anyone can give me
Thanks in advance
put def messageSource (in controller or service)
item.errors?.allErrors?.each{
println messageSource.getMessage(it, null)
};
I also found a good link which explains this better
http://johnrellis.blogspot.com/2010/02/retrieve-grails-domain-errors-from.html
Well, the documentation shows you an example of how to override the messages for one of the default Validation Constraints (blank, nullable, min, max, size, range, etc.). But it fails to tell you to look in the documentation for each Constraint and at the bottom it shows you what propery key to use:
Error Code: className.propertyName.size.toosmall or className.propertyName.size.toobig
for Constraint size http://grails.org/doc/latest/ref/Constraints/size.html
So, for
package com.example
class User {
String username
static constraints = {
username size:5..15
}
}
use:
com.example.User.username.size.toosmall=Yo there! too small: [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}]
com.example.User.username.size.toobig=Yo there! too big: [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}]
It might be that your constraints aren't static - it should be specified as "static constraints = { ..."
Also note that nullable defaults to false so you don't need to specify that.
I use fully qualified class names in my messages.properties
com.shareyourlove.User.password.blank=Some custom message
This worked for me
com.model.Customer.name.nullable.error = Custom message
instead of
com.model.Customer.name.blank = Custom message

Resources