I'm sure this is a total noob question and I'm missing a blatant error, but here goes anyway.
I have a command object:
public class LeadCommand {
Integer OwnerId
String FirstName
String LastName
String Email
String Phone1
String Company
String StreetAddress1
String City
String State
String PostalCode
String Country
String Leadsource
static constraints = {
OwnerId(blank: false)
FirstName(blank: false)
LastName(blank: false)
Email(blank: false, email: true)
Phone1(blank: false)
Company(blank: false)
StreetAddress1(blank: false)
City(blank: false)
State(blank: false)
PostalCode(blank: false)
Country(blank: false)
Leadsource(blank: false)
}
}
And a controller action:
def process = { LeadCommand cmd ->
if (cmd.hasErrors()) {
redirect(action: index)
} else {
// do stuff
}
}
The command object is getting populated, but is not following the validation constraints that I setup. I've read through the docs a couple of times, but I must be missing something...
Thanks in advance
BTW - I'm using Grails 1.3.7
EDIT:
Here is some sample post data: (straight from params map)
[Phone:,
OwnerId:1,
Country:United States,
LastName:,
City:,
PostalCode:,
State:,
Email:,
Leadsource:,
FirstName:,
Submit:Submit,
Company:,
StreetAddress1:,
action:process,
controller:leadEntry]
Rename your command properties to use the standard Java naming convention of camel case with an initial lower case letter. Grails uses these conventions heavily and sometimes breaks if you don't follow them. For example:
public class LeadCommand {
Integer ownerId
String firstName
String lastName
String email
String phone1
String company
String streetAddress1
String city
String state
String postalCode
String country
String leadsource
static constraints = {
ownerId(blank: false)
firstName(blank: false)
lastName(blank: false)
email(blank: false, email: true)
phone1(blank: false)
company(blank: false)
streetAddress1(blank: false)
city(blank: false)
state(blank: false)
postalCode(blank: false)
country(blank: false)
leadsource(blank: false)
}
}
Related
when I use TryUpdateModelAsync method to update Model I give this error, any one have an idea about this
The passed expression of expression node type 'NewArrayInit' is invalid. Only simple member access expressions for model properties are supported.
Code for this issue is as below.
[HttpPost,ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EditLocaton([ModelBinder(typeof(EncryptDataBinder))]int id, IFormCollection formCollection)
{
ModelState.Clear();
LocationModel location = new LocationModel();
try
{
await TryUpdateModelAsync<LocationModel>(location, "", p => new object[] { p.ID, p.Name, p.Code, p.RowVersion });
code for the Location Model
public class LocationModel : BaseEntity
{
[Required]
[StringLength(100)]
[Display(Name = "Location Name")]
public string Name { get; set; }
[Required]
[StringLength(20)]
public string Code { get; set; }
[NotMapped]
public string enID { get; set; }
}
Please help for this issue.
Here's a sample for TryUpdateModelAsync.
var studentToUpdate = await _context.Students.FirstOrDefaultAsync(s => s.ID == id);
if (await TryUpdateModelAsync<Student>(
studentToUpdate,
"",
s => s.FirstMidName, s => s.LastName, s => s.EnrollmentDate))
{
try
...
It updates the studentToUpdate using data provided in the incoming request.
So I'm afraid you can try await TryUpdateModelAsync<LocationModel>(location, "", p => p.enID, p => p.Name, p => p.Code);. In your code snippet, I don't find RowVersion in your LocationModel, not sure about it.
I have a model class (simplified below):
public class Person
{
[JsonRequired]
[RegularExpression(#"^[ -'A-Za-z]{2,30}$", ErrorMessage ="The field firstName must be between 2 and 30 characters and contain alpha characters only.")]
[JsonProperty(PropertyName = "firstname")]
public String Firstname { get; set; }
[RegularExpression(#"^[ -'A-Za-z]{2,26}$", ErrorMessage = "The field middleName must be between 2 and 26 characters and contain alpha characters only.")]
[JsonProperty(PropertyName = "middlename")]
public string Middlename { get; set; }
}
The decorators work when I fire the API from Postman - and the error is returned.
I am currently creating UNIT Tests and want to check the validation but manual assignment through code allows it through e.g.
Person testPerson = new Person();
testPerson.middlename = "Bob123";
and therefore the Unit Test passes (or fails depending on your point of view!)
Is there a simple way through Unit Tests to check for this type of validation?
OK. So the below does what I need:
Person testPerson = new Person();
testPerson.middlename = "Bob123";
var validationResults = new List<ValidationResult>();
var context = new ValidationContext(testPerson);
Validator.TryValidateObject(testPerson, context, validationResults, true);
And looking at the "validationResults" reveals the particular error message of the field that fails - e.g. middlename.
POSTMAN :
{
"childDTO":[{
"age":"80",
"gender":"kavi",
"occupation":"main",
"type":"mainlife"
},
{ "age":"80",
"gender":"kavi",
"occupation":"main",
"type":"mainlife"
}
]
}
Controller.....
#PostMapping("/child")
public List<CustomerDTO> childDTO(#RequestBody CustomerDTO cus){
return calculationService.childDTO(cus.getAge(),cus.getGender(),cus.getOccupation(),cus.getType());
}
Service......
public List<CustomerDTO> childDTO(String age, String gender, String occupation, String type);
Service Impl......
#Override
public List<CustomerDTO> childDTO(String age, String gender, String occupation, String type) {
List<CustomerDTO> typeChild = new ArrayList<>();
if (type==children) {
for (CustomerDTO customer1 : typeChild) {
customer1.setAge(age);
customer1.setGender(gender);
customer1.setOccupation(occupation);
customer1.setType(type);
customer1.setBenifits(benifitDTO(beni.getRiders(), beni.getSumAssuarance()));
System.out.println("list:-"+customer1);
typeChild.add(customer1);
}
}
System.out.println("list:-"+typeChild);
return typeChild;
}
You did not post what variable children is, probably some class field, but you cannot compare Java Strings with ==. Java Strings must be compared with .equals:
...
if (type.equals(children)) {
...
Use a debugger next time, to see what's happening in your code.
Your request and controller RequestBody structure do not match.
You need to use List.
#PostMapping("/child")
public List<CustomerDTO> childDTO(#RequestBody List<CustomerDTO> cusList){ // here list needs to be used
if(cusList != null && !cusList.isEmpty()) {
CustomerDTO cus = cusList.get(0); // it will get first element from the list, if you want to process all the elements then you need to iterate the list
return calculationService.childDTO(cus.getAge(),cus.getGender(),cus.getOccupation(),cus.getType());
}
}
Now other logic will be as it or you may change it as per your requirement.
In my code, I am returning a path in String form(/successPassword or /systemError). Basically this tells Spring to go to the path /successPassword or /systemError, /successPassword goes to successPassword.html and /systemError goes to systemError.html. These html files are located in src/main/resources/templates.
#RequestMapping(value = "/user/new_password", method = RequestMethod.POST)
public String createNewPassword(#RequestParam(value = "newpassword", required = false) String password,
#RequestParam(value = "hash") String hash, Model model) {
LOG.info("set new password using hash " + hash);
LOG.info("new password " + password);
boolean hashValid = passwordService.isHashValid(hash);
if (hashValid) {
ValidateMessage message = passwordService.validateNewPassword(password);
if (!message.isError()) {
Account account = passwordService.getAccount(hash);
passwordResetService.saveNewPassword(password, account);
model.addAttribute("account", account);
return "/successPassword";
} else {
LOG.info("Password not complex enough.");
return "/systemError";
}
} else {
LOG.info("Invalid hash.");
return "/systemError";
}
}
Now it looks like I need to return a json object instead. I know that I have to annotate the method with #ResponseBody instead, but my question is how would i package now the object that I will return so that whoever receives it will know to which path it needs to go to? My html codes are using Thymeleaf (no javascript whatsoever).
in my current project, i was so stupid to make an API which expects the variable private. in the controller it gets mapped to isPrivate, but now i wanted to make a commandObject (#validatable) to check if everything is valid. How can i map the private variable using autobinding on isPrivate?
#Validateable
class EventCommand{
boolean isPrivate
boolean fullDay
String title
String location
String description
static constraints = {
location(nullable: true)
description(nullable: true)
fullDay (nullable: false)
isPrivate(nullable: false)
title (blank: true, nullable: false)
}
}
and the code where the databinding happens (inside a grails controllor):
def add() {
def jsonData = request.JSON
EventCommand command = new EventCommand(jsonData)
if(!command.validate()){
throw new QuivrException(command)
}
boolean isPrivate = jsonData.private
//some things happen, uninmportant
}
i already tried using the #BindUsing annotation, but i always keep getting the error that EventCommand has no property named "private" (the matches works, but he tries to match private to something none-existant)
is there any way to solve this without changing the received private to isPrivated (already got old versions of the application and got 20% not on latest version)
Well from your jsonData remove the private property and then do the binding and after binding add the private manually from a variable in which you should be getting the private value.
Hence your add could be something like
def add() {
def jsonData = request.JSON
String isPrivate = jsonData.private
jsonData.remove("private")
EventCommand command = new EventCommand(jsonData)
if(!command.validate()){
throw new QuivrException(command)
}
command.isPrivate = isPrivate as Boolean
}