Grails: Debugging save() or validate() - grails

I'm somewhat new to Grails. As I create or update domain object and fire save() or validate() on an object, if the method fails, the system does not seem throw an exception. I dont see any way to examine what exactly is failing.
A typical snippet:
if (domainInstance.validate()) {
flash.message = "Succesfully updated domain object"
} else {
flash.message = "Failed to update domain object"
//throw new RuntimeException("Invalid broker")
log.error "Failed to update domain object"
}
In my case the validate fails, and I am in the dark as to why.
Could anybody shed some light on it?
If placed into a try/catch, this does not throw an exception.

mydomain.validate() is used to only validate the object. You may use mydomain.hasErrors() to load the errors object and to print what went wrong with the following statement.
if(mydomain.hasErrors()){
mydomain.errors.allErrors.each{println it}
}
And generally the way I prefer to save and update any object is
if(mydomain.hasErrors() || !mydomain.save(failOnError:true){
//action to be taken if domain validation fails.
}
By setting failOnError:true, if the save() fails, validation exception would be thrown which needs to catched in controller.

You can also set failOnError = true for the entire application in the grails config file
grails.gorm.failOnError=true
http://www.grails.org/doc/1.3.x/guide/3.%20Configuration.html#3.1.3 GORM

Related

breeze entitiesWithErrors not found but instead found entityErrors

The error object that is returned from breeze manager saveChanges() don't have the array entitiesWithErrors, but instead has the entityErrors array (perhaps is as it is on breeze.js version: 1.4.12, metadataVersion: 1.0.5)
The returned error object looks like...
Error {stack: "Error: Client side validation errors encountered", entityErrors: Array[6], message: "Client side validation errors encountered see the Errors collection on this object for more detail" entityErrors: Array[6] bla. bla..
Thus the code bellow will fail and I will need to refactor it if I am not able to work with entitiesWithErrors
function getErrorMessages(error) {
function getValidationMessages(err) {
try {
return err.entitiesWithErrors.map(function (entity) {
return entity.entityAspect.getValidationErrors().map(function (valError) {
return valError.errorMessage;
}).join('; <br/>');
}).join('; <br/>');
} catch (e) {
}
return 'validation error';
}
var msg = error.message;
if (msg.match(/validation error/i)) {
return getValidationMessages(error);
}
return msg;
}
This breaking change was made in Breeze version 1.4.0. From the release notes,
The description of client side validation errors caught during a save
before posting to the server has changed.
Client side validation errors caught during a save, but before posting
to the server, cause the save to fail and be routed to the fail
promise. The fail promise returns an error object that contains a
description of the errors. This description has changed.
Previously this error object contained an entitiesWithErrors property
that contained a list of all of the entities that had failed
validation. This property has now been replaced with the entityErrors
property. The entityErrors property returns a collection of
entityError objects as described above.
This change was made in order to retain consistency between save
failures that occurred on the server and those that failed before
posting to the server on the client.
To refactor your code, you simply do,
return error.entityErrors.map(function (entityError) {
return entityError.errorMessage;
})

AccountController not redirecting to the correct page when using Active Directory authentication

I am modifying the AccountController to use a separate class that queries Active Directory for information and stores that info in the Login Model. In my account controller I have this:
try{
LDAPAuth.LDAPQuery(model);
return RedirectToAction("Homepage", "HomePage");
}
catch (Exception e)
{
throw new Exception(e.message);
}
I am surrounding it in a try/catch becasue if the DirectorySearcher did not find the user it will tell them that the username or passwrod is wrong and I am just trying to pass the exception on the view. What is happening is that when it gets inside the try block the model is set perfectly fine with the attributes I want but the redirection takes me to
http://localhost:7606/Account/Login?ReturnUrl=%2fHomePage%2fHomepage
LDAPAuth class is implemented according to this solution, I also surrounded this in try/catch to catch invalid users which I am trying to pass to the View
http://stackoverflow.com/questions/1295157/how-do-i-query-activedirectory-using-ldap-with-a-username-not-a-cn
I am not sure what is the problem and debugging it is not helping either.
I hope somebody can help! Thanks
Before you redirect to action, issue a FormsAuthentication.SetAuthCookie. This should override the default behaviour of the return URL:
Its also worth noting that the bool in SetAuthCookie(string username, bool createPersistantCookie) can be used to remember the user. For this example I have set it to false.
try{
LDAPAuth.LDAPQuery(model);
FormsAuthentication.SetAuthCookie(model.UserName, false);
return RedirectToAction("Homepage", "HomePage");
}

Concurrency/ToDo Sample not working

I was trying out the ToDo sample and ran into an unhandled Excaption while trying out the Concurrency Handling.
The dataservice.js contains these lines in saveFailed(error) method:
if (detail && detail.ExceptionType.indexOf('OptimisticConcurrencyException') !== -1) {
// Concurrency error
reason =
"Another user, perhaps the server, may have deleted one or all of the todos.";
manager.rejectChanges(); // DEMO ONLY: discard all pending changes
}
The client never gets to this point due to an unhandled OptimisticConcurrencyException in:
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle) {
return _contextProvider.SaveChanges(saveBundle);
}
I was trying to catch this and return the Exception which was kind of stupid as the Exception is not of type SaveResult. Is this a bug or am i missing an configuration somewhere?
Greets
Any server side errors should be returned to the promise.fail handler. i.e.
em.saveChanges().then(function(saveResult) {
// normal path
}).fail(function(error) {
// your concurrency exception message will be part of the error object.
});
Error on my side here... Clicking 'Continue' on the Exception Windows in VS the javascript handler is executed.

FluentNhibernate configuration exception handling in application_start

I am initializing FluentNHibernate from Application_Start event like so:
Fluently.Configure()
.Database(OracleDataClientConfiguration.Oracle10
.Driver<NHibernate.Driver.OracleDataClientDriver>()
.ConnectionString("MyConnectionString")
.DefaultSchema("MySchema")
)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<SomeClass>())
.BuildConfiguration()
.BuildSessionFactory();
If the connection string is bad, or connection to the DB fails for some other reason, I get a TNS No listener exception. I would like to display/log this exception but Application_Start (and Applicaiton_Error) doesn't have an HttpContext or Response object in IIS7 Integrated mode. The user gets a yellow screen of death telling them to turn custom errors On. Elmah doesn't log the message either. I would like to solve the problem in one of two possible ways:
Disable nhibernate configuration from connecting to the database on configuration.
Provide custom user feedback based on the error and get Elmah working (somehow). This would be my ideal choice.
I was able to move NHibernate configuration to run on Session_Start, as described here, which gets exception handling working for this error, but then I get other exceptions that can be misleading to the root cause of the problem. Does anyone have a good solution for this scenario?
Thank you.
This is what I do:
void Application_Start() {
try {
// setup your app / nhibernate
} catch(Exception ex) {
Application["StartupError"] = ex
}
}
void Application_BeginRequest() {
var startupError = Application["StartupError"] as Exception;
if (startupError != null)
throw new Exception("Error starting application", startupError);
}
In your BeginRequest method you have access to the Request and can do what you want to show the error (or show a nice page)

JSR303 ConstraintValidator, how to show the message without an error page

Im working with JSF 2.0 and Glassfish v3. I was testing the functionality of JSR303 bean validation, so I created a validator which implements ConstraintValidator and then annotate that on a property wich I want to validate.
It works fine, but it displays a Glassfish default error page. I don't want this to be displayed, I would rather have the message displayed in a <h:outputText> or something.
Does anybody know how to achieve this?
Here is my validator method:
#Override
public boolean isValid(String searchArg, ConstraintValidatorContext ctx) {
boolean searchArgCorrect = true;
FacesMessage msg;
if(searchArg!=null) {
ctx.disableDefaultConstraintViolation();
if(searchArg.length() < 3) {
ctx.buildConstraintViolationWithTemplate("Searcharg is too short").addConstraintViolation();
searchArgCorrect=false;
msg = new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"Searcharg is too short", null);
throw new ValidatorException(msg);
}
}
return searchArgCorrect;
}
PS: I know that there are easier ways to validate the length of a string, but the above code snippet is only for demo/testing purposes. I have another plans with the validator.
You're mixing two concepts: JSF validation and JSR 303 bean validation. You're implementing JSR303 bean validation, but you're throwing a JSF-specific ValidatorException.
The method should not throw an exception. The method should just return true or false depending on the validation outcome. The message has to be definied in ValidationMessages.properties. JSF will then display it in a <h:message> which is associated with the input component.
See also this documentation on creating custom constraints with a message.
Or if you're actually after a standard JSF validator, then you should be implementing javax.faces.validator.Validator instead, annotate it with #FacesValidator and declare it in view by <f:validator>. It can throw a ValidatorException and the message will be displayed in <h:message> associated with the input component.

Resources