The usual way of constraint validating domain objects in Grails is by defining a static constraints closure in the domain object, after which one can call myObject.validate().
Is it possible in some way to pass what should be validated to the validate call and not define a constraints block?
I guess it could be done with Spring validator instances, but is there an easier way where you still have the "goodies" from Grails (max, email, etc.)?
You can pass a list of fields into .validate(["fieldA", "fieldB"]) and it will only validate those fields. You still need a constraints block to define what the constraints are for those fields.
From Grails User Guide:
"The validate method accepts an optional List argument which contains the names of the properties to be validated. When a List of names is specified, only those properties will be validated."
To respond to #eugene82:
#Validateable
class MyDomainValidator {
String email
static constraints = {
email(email:true)
}
}
MyDomain m = new MyDomain()...
MyDomainValidator mv = new MyDomainValidator()..
mv.properties = m.properties
mv.validate()
I imagine such an approach: Create a #Validateable groovy class with static constraints inside with any Grails goodies you need. Let it own all fields like your domain does (e.g. by extending the domain), and provide a way to copy all fields from a domain instance to a new instance of that object, e.g. using a constructor. Than call validate() on that class.
class MyDomain {
String email
MyDomain() {}
MyDomain(email) {
email = this.email
}
}
#Validateable
class MyDomainCustomValidator extends MyDomain {
MyDomainValidator() {}
MyDomainValidator(domain) {
super(domain.email)
}
static constraints = {
email email: true
}
}
def d = new MyDomain('e#mail.com')
new MyDomainCustomValidator(d).validate()
Related
As per docs, kotlin var properties can be bind in ViewModel as
// Kotlin var property
class PersonVarViewModel(person: Person) : ViewModel() {
val name = bind { person.observable(Person::name) }
}
It seems like doesn't work.
How to solve this issue. IDE shows red underline bellow "bind"
but if i write
val name = bind(RoomType::name)
it shows no error. but updating the value using UI fields does'nt update the model value.
Please help
In your class declaration, use var person: Person.
person needs to be a member of the class, not just a parameter to the constructor. You can do this by declaring it var or val in the constructor parameters, or you can add a member field to the class the conventional way and assign it (probably using by property, but not sure if that's what you want)
class PersonVarViewModel(var person: Person) : ViewModel() {
val name = bind { person.observable(Person::name) }
}
For ItemViewModel ...
class PersonVarViewModel(var person: Person) : ItemViewModel<Person>() {
val name = bind { person.observable(Person::name) }
}
You need to make the ItemViewModel aware of the person instance, but also let it react to changes to the underlying item later. You need to assign the person you pass in to the item property of the ItemViewModel. This can be done by passing it in the constructor:
class PersonVarViewModel(person: Person) : ItemViewModel<Person>(person) {
val name = bind(Person::name)
}
Be aware that if you add this constructor, you can only use the that viewmodel with injection if you push it manually into scopes, since it can't be instantiated by the framework. You should therefore either add a noargs constructor as well, or simply omit the person parameter and assign to item after you create it.
If you update the value in the underlying person, it will only be visible in the view model if the value is observable. If not, you have to call rollback() to update changes from the person. You can call rollback for specific fields only.
If possible, use observable properties in your domain model objects to avoid such issues.
i am new in mvc .here scott shows how to Creating a Custom [Email] Validation Attribute in mvc. here is the picture.
http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx
1) now see how they did it. first create a class give a name and extend regular expression attribute class and in its ctor they use regex to validate email address
my question is when they use [Email(Errormessage="blah blah")]
then how MVC can understand this email attribute is pointing to email attribute class which extend regularexpression attribute class. how relation will be extanlish. the class name is email attribute but when they use then they use attribite name email. this is not clear to me please explain.
2) if i validate the email the above way they where validation will occur means at server side or client side ?
if not client side then how can i make it client and required js will be render for that.
please explain me with sample code example. thanks
The first question is best answered with a principle widely used in MVC: convention over configuration. That basically means: do the less config possible, use the most default functionalities. Several examples in ASP.NET MVC
Folder Controllers contain controllers by default.
The name of a view corresponds to the name of a Action in a Controller.
The folder name where a view is located corresponds to the Controller name without 'Controller' ending.
The class name of the controller ends with 'Controller' which is omitted when calling the controller.
The same with Attributes; the class name ends with 'Attribute' which is omitted in usage
etc, etc, etc,
There are many more like this and it is not configured. It is convention.
The second question is already partially answered in the question itself: you cannot inherit from EmailAddressAttribute as it's a sealed class. But you can use
RegularExpressionAttribute the way it's described in your question, or create a new attribute, like I will do it below.
However this way the validation will take place only on server side. To make it on client side you need to do the following:
public class EmailAttribute : ValidationAttribute, IClientValidatable
{
private const string VALIDATION_TYPE = "customEmail";
private const string EMAIL_REGEX = #"put your regex here";
public virtual IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule { ValidationType = VALIDATION_TYPE, ErrorMessage = ErrorMessageString };
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var sValue = value as string;
if (!string.IsNullOrEmpty(sValue) && Regex.Match(sValue, EMAIL_REGEX).Success)
{
return ValidationResult.Success;
}
return new ValidationResult(string.Format(ErrorMessageString, validationContext.MemberName));
}
}
Then in Javascript (I suppose you've included jQuery, jQuery.validate and jQuery.validate.unobtrusive) use the following:
$.validator.addMethod('customEmail', function (value, element) {
let regex = /put your regex here/;
return regex.test($(element).val());
});
$.validator.unobtrusive.adapters.add('customEmail', [], function (options) {
options.messages['customEmail'] = options.message;
options.rules['customEmail'] = options.params;
});
When using command objects like:
class UserCommand {
String name
static constraints = {
name blank: false, unique: true, minSize: 3
}
}
you can use them to validate objects without making them persistent. In my case I would validate for a persistent class User.
In controller:
def save(UserCommand cmd) {
if(!cmd.validate()) {
render view: "create", model: [user: cmd]
return
}
def user = new User()
user.name = cmd.name
user.save()
redirect uri: '/'
}
in messages.properties:
user.username.minSize.error=Please enter at least three characters.
userCommand.username.minSize.error=Please enter at least three characters.
When using custom validation messages you have to write the message codes for each error twice. One for the User class and another for the UserCommand class.
Is there a way how I can have only one message code for each error?
I might be wrong here but if you're using just the stock Grails constraints, the only way to share a validation message is to simply rely on the default.x.x.message key/values in messages.properties. Otherwise messages are looked up via the following key form:
className.propertyName.errorcode...=
You can however use a custom validator and override what message key gets returned for the validation error.
class User {
...
static constraints = {
...
name blank: false, unique: true, validator: { value, user ->
if(!value || value.length() < 3)
return 'what.ever.key.in.messages.properties'
}
}
}
Then you can keep it all DRY by sharing constraints between classes via a global constraint or as #dmahapatro mentioned, with the use of an importFrom in your UserCommand like so,
class UserCommand {
...
static constraints = {
importFrom User
...
}
}
If you have more complicated validation, you can create your own constraints classes. Here are some resources:
http://www.zorched.net/2008/01/25/build-a-custom-validator-in-grails-with-a-plugin/
http://blog.swwomm.com/2011/02/custom-grails-constraints.html
using unique constraint in CommandObject makes no sense, because uniqueness of what would it check?
you can validate domain objects without persisting them exactly the same way as command objects - using validate() method
you can put a User object in command object, set constraints only for the domain class, and then validate User object being a part of command object
class User {
String name
static constraints = {
name blank: false, unique: true, minSize: 3
}
}
class UserCommand {
User user
static constraints = {
user validator: { it.validate() }
}
}
user.username.minSize.error=Please enter at least three characters.
I want to validate three form fields.
The usual method is like this:
class User {
String name
String password
String personalInfo
static constraints = {
name(size: 4..20, unique:true, blank:false)
password(size:8..20, blank:false)
personalInfo(size: 1000, nullable:true)
}
}
but in my gsp i'll be having all three textfields in the same name
eg:
<td>Name:</td><td><g:textfield name="property"/></td>
<td>Password:</td><td><g:textfield name="property"/></td>
<td>PersonalInfo:</td><td><g:textfield name="property"/></td>
How to validate this form????
It is a really bad practice to give the same name to input fields in a form that are going to be mapped to different properties in the same domain class.
But if you cant, the fields will be sent as a list to your controller. So you can extract values in the controller like this:
def parameterList = params.property as List
def name = parameterList[0]
def password = parameterList[1]
def personalInfo = parameterList[2]
Then you can create your User object
def user = new User(name:name, personalInfo:personalInfo, password:password)
if (user.save()){ } else{ }
As the best practice you must name your fields in the form differently
I am implementing ACL security using the spring-security-acl plugin. I have the following domain classes:
package test
class Subitem {
String name
static belongsTo = [employer: Employer]
static constraints = {
name blank: false
}
}
package test
class Employer {
String name
static hasMany = [users: User, items: Subitem]
static belongsTo = User
static constraints = {
name blank: false, unique: true
}
String toString() {
name
}
}
In the create.gsp file which is used to create a Subitem, there is the following statement:
<g:select id="employer" name="employer.id" from="${test.Employer.list()}" optionKey="id" required="" value="${subitemInstance?.employer?.id}" class="many-to-one"/>
From the EmployerController:
def list = {
params.max = Math.min(params.max ? params.int('max') : 10, 100)
[employerInstanceList: employerService.list(params),
employerInstanceTotal: employerService.count()]
}
Following the tutorial given here, I have moved some of the functionality with dealing with Employer to a service called EmployerService:
#PreAuthorize("hasRole('ROLE_USER')")
#PostFilter("hasPermission(filterObject, read)")
List<Employer> list(Map params) {
Employer.list params
}
int count() {
Employer.count()
}
Access to information in any given Employer class instance is restricted using ACL. At present, I can see ALL instances of Employer in the database in the drop down, and I assume that is because I am using the controller list(), not the service list() - however, I only want to see the filtered list of Employer domain classes. However, if I replace the g:select with:
<g:select id="employer" name="employer.id" from="${test.EmployerService.list()}" optionKey="id" required="" value="${subitemInstance?.employer?.id}" class="many-to-one"/>
then I get an internal server error because I haven't passed a Map parameter to the service list() function (and I don't know how to do this within the tag):
URI /security/subitem/create
Class groovy.lang.MissingMethodException
Message No signature of method: static test.EmployerService.list() is applicable for argument types: () values: [] Possible solutions: list(java.util.Map), is(java.lang.Object), wait(), find(), wait(long), get(long)
I only want to see the information that comes from the EmployerService list() function - how do I do this please? How do I reference the correct function from within the gap?
Edit 16 Mar 0835: Thanks #OverZealous, that's really helpful, I hadn't realised that. However, I've tried that and still get the same problem. I've put a println() statement in both the Employer and EmployerService list() functions, and can see that neither actually seems to get called when the g:select tag is parsed (even if I leave the g:select to refer to Employer). Is there another version of the list() function that is being called perhaps? Or how else to get the g:select to take account of the ACL?
Just change your method signature in the Service to look like this:
List<Employer> list(Map params = [:]) {
Employer.list params
}
The change is adding this: = [:]. This provides a default value for params, in this case, an empty map.
(This is a Groovy feature, BTW. You can use it on any method or closure where the arguments are optional, and you want to provide a default.)
OK, I worked it out, and here is the solution to anyone else who comes up against the same problem.
The create Subitem page is rendered by means of the Subitem's create.gsp file and the SubitemController. The trick is to amend the SubitemController create() closure:
class SubitemController {
def employerService
def create() {
// this line was the default supplied method:
// [subitemInstance: new Subitem(params)]
// so replace with the following:
params.max = Math.min(params.max ? params.int('max') : 10, 100)
[subitemInstance: new Subitem(params), employerInstanceList: employerService.list(params),
employerInstanceTotal: employerService.count()]
}
}
So now when the SubitemController is asked by the g:select within the Subitem view for the list of Employers, it calls the EmployerService, which supplies the correct answer. We have simply added 2 further variables that are returned to the view, and which can be referenced anywhere within the view (such as by the g:select tag).
The lesson for me is that the View interacts with the Controller, which can refer to a Service: the Service doesn't play nicely with a View, it seems.