Grails - Domain object doesn't validate correctly - validation

I'm trying to set the date of birth of a person using jQuery Datepicker. However, all I get is that the Property dateOfBirth must be a valid Date.
So, originally, my controller looks like this:
def update(Person personInstance) {
if (personInstance == null) {
// do Something
return
}
if (personInstance.hasErrors()) {
respond personInstance.errors, view: 'edit'
return
}
// do the rest
}
I figured out, that with jQuery I should use a SimpleDateFormat object in order to generate a proper Date object. Nevertheless, even if I directly assign a new Date object to dateOfBirth and subsequently validating the personInstance domain object - like in the following code segment - I still get the Property dateOfBirth must be a valid Date error.
def update(Person personInstance) {
if (personInstance == null) {
// do Something
return
}
// added code
personInstance.dateOfBirth = new Date()
personInstance.validate()
// added code
if (personInstance.hasErrors()) {
respond personInstance.errors, view: 'edit'
return
}
// do the rest
}
Thank you for any help :)

The reason why you are still seeing errors is because validation is automatically called after binding your command/domain object when the method is called.
Use personInstance.clearErrors() before calling personInstance.validate() manually to clear out any existing binding/validation errors. You can see more about this in the documentation.

Related

To create a session explicitly for first the first time page loads in Grails

As soon as a page loads, it renders a lot of data and shows on the view which sort of slows down the performance. I want to restrict this and load the data only when a filter is applied .
I need a way in which a session variable can store the value on the 1st login and no data should be loaded in that 1st session i.e. when any user loads it for the very first time using his login. something like the below in the controller class:
if(session.dtstartDate && session.dtstartDate != '')
{
SimpleDateFormat nsdf = new SimpleDateFormat('yyyy-MM-dd')
Date startDateValue = nsdf.parse(session.dtstartDate.substring(0, session.dtstartDate.lastIndexOf("T")))
eq("startDate", startDateValue)//if any filter is applied
}
else{
if this is the 1st session the startdate should be null --> need a piece of code to be replaced here
}
I am unsure maybe I still have not got what you have tried to ask properly, I thought I should try to answer your question to how I understood your problem to be.
If we take this basic filter and add some stuff to it we may be able to get to what you wish to do using a better method ? I am unsure what startDate is actually representing but if we base it on if a user has hit a controller for the first time or not the answer would be something like this, you could replace the logic to startDate if it has other significance:
so adding some hashmap arrayset to your filter that gets called before the action is called when user clicks the controller/action:
in your conf/MyFiters.groovy
class MyFilters {
static final Set<HashMap<String[],String[]>> userControl =
([:] as Set).asSynchronized()
//where controller is controllerName and action is actionName
def filters = {
MyLogger() {
before = {
if (verifyClientMaster(session.id as String ,controllerName)==false) {
clientMaster.add(session.id as String:controllerName)
// now here you have a new user so set
// some session value for gsp or load something
//according
}else{
// user has hit it before do something else or set something else
}
}
}
}
}
Boolean verifyClientMaster(String sessionId,String controller) {
// iterate
boolean found = false
userControl.each { k,v -> if (k == sessionId && v == controller) {
found = true
}
}
}
something like this and you know if the user has hit the controller or not.. remember the session is per user. so a new user has a new session entity.
Hope it is of help and not off track..
E2A
Thinking about it you do go down this route then you would need to keep track of when session expires and to remove the user from clientMaster.. take a look at this project if you did go down this route.. personally I would even do it simpler than this... on a rethink...
class MyFilters {
def filters = {
MyLogger() {
before = {
if (!sessions."${controllerName}") {
sessions."${controllerName}"="${controllerName}"
// now here you have a new user so set
// some session value for gsp or load something
//according
}else{
// user has hit it before do something else or set something else
}
}
}
}
}
and even simple than any of this would be to use the intelligence built into a gsp if what you load can be based on it... (not tested any of it ha)
<g:if test="${!session."${controllerName}"}">
<g:set var="${controllerName}" value="${controllerName}" scope="session" />
<g:render template="firstTimeHitter"/>
</g:if>
<g:else>
<g:render template="secondTimeHitter"/>
</g:else>
or just your controller that checks and sets that and either renders something different or sets something gsp picks up on..
def myController {
def doSomething() {
boolean firstTime = false
if (!session."${controllerName}") {
// first time either render or set firsTime
firstTime = true
session."${controllerName}" = controllerName // or startDate
// render view: 'firstTime, model: [firstTime:firstTime, params:params]
} else{
// render view: 'firstTime, model: [firstTime:firstTime, params:params]
}
// if no render above:
render view: 'doSomething, model: [firstTime:firstTime, params:params]
// now in doSomething gsp you look for firstTime:
}
do someThing:
<g:if test="${firstTime.toString().equals('true')}">
<g:render template="firstTimeHitter"/>
</g:if>
<g:else>
<g:render template="secondTimeHitter"/>
</g:else>
The possibilities are endless, the differences being with a filter its a one fits all, i.e. it is checking every controller as it is hit by each user. In controller and gsp solution you have to declare it where needed. You could have an abstract controller that other controllers extend to repeat that check as a higher class that gets called to verify, regardless their all a lot more repetitive than a simple one off filter...
Final Edit to give other other alternatives would be:
final Set<Session> jsessions = ([] as Set).asSynchronized()
jsessions.add('controller1')
jsessions.add('controller2')
jsessions.add('controller3')
jsessions.add(controllerName)
println "=== ${jsessions}"
if (jsessions.contains(controllerName)) {
println "--- We have ${controllerName} defined in our session set.... jsessions"
}
ArrayList jsessions2 = []
jsessions2.add(controllerName)
session.jsessions2 = jsessions2
//repeat this on every call
ArrayList jsessionsret = session.jsessions2
jsessionsret.add('controller1')
jsessionsret.add('controller2')
jsessionsret.add('controller3')
session.jsessions2 = jsessionsret
if (jsessions2.contains(controllerName)) {
println "--- We have ${controllerName} defined in our session set.... jsessionsret"
}
println "222 --- ${jsessions2}"
This segment above are two different implementations of using first a session set that is global and could be used if you do not care if the controller is hit by usera userb etc so if usera hits it userb would also be considered as hitting it.. This is jsessions.
The bottom jsessions2 is an attempt to turn a single session key into an ArrayList. So rather than storing lots of single object i.e. session."${controllerName}" per call of a controller per user session. You could have 1 single session key per user that you append each controller they hit to.. and you then check to see if they have that controller

Web API validation error

I have a View Model called SignUp with the EmailAddress property set like this:
[Required]
[DuplicateEmailAddressAttribute(ErrorMessage = "This email address already exists")]
public string EmailAddress { get; set; }
and the custom validator looks like this:
public class DuplicateEmailAddressAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
PestControlContext _db = new PestControlContext();
int hash = value.ToString().GetHashCode();
if (value == null)
{
return true;
}
if (_db.Users.Where(x => x.EmailAddressHash == hash).Count() > 0)
return false;
else
return true;
}
}
The problem I'm having is that if the user leaves the email address field blank on the sign up form the application is throwing a null reference exception error (I think it's looking for "" in the database and can't find it). What I don't understand is why this isn't being handled by the Required attribute - why is it jumping straight into the custom validator?
The Required attribute would have resulted in an error being added to the model state. It will not short-circuit the execution though. The framework continues to run other validators for the simple reason that all the errors about the request need to be sent out in a single shot. Ideally, you wouldn't want the service to say something is wrong to start with and when the user re-submits the request after making a correction, the service comes back and say some other thing is wrong and so on. It will be an annoyance, I guess.
The NullReferenceException is thrown because value.ToString() is called before the check against null. As you need the hash variable only after the check, you can solve this by reordering the statements:
if (value == null)
{
return true;
}
int hash = value.ToString().GetHashCode();
In addition, you could also move the PestControlContext after the check against null and use a using statement to dispose of it properly.
As also #Baldri pointed out, each validator can add Error messages and all of them are run, even if a previous one already signaled the data to be invalid. Furthermore, I'd not rely on that the validations are run in the order that you specify when marking the property with the attributes (some frameworks implement their own attribute ordering mechanism in order to assert that the order is deterministic, e.g. priorities or preceding attributes).
Therefore, I suggest reordering the code in the custom validator is the best solution.

ASP.NET MVC3 using Redirect To Action

I want to use the Redirect to Action result on this code which gives a null but i have several if statements and the code is becoming more complex to build need a solution on how i could use the Redirect to Action which outputs null, help please?
public ActionResult Convert(double temperature, string convertTo)
{
ViewBag.Temperature = temperature;
ViewBag.ConvertTo = convertTo;
if (convertTo.Equals("Celsius"))
{ ViewBag.ConvertedTemperature = this.FahrenheitToCelsius(temperature); }
else
{ ViewBag.ConvertedTemperature = this.CelsiusToFahrenheit(temperature); }
return View("Convert");
}
The error message would really help. But it seems like you'd need to make your temperature parameter nullable, like so:
public ActionResult Convert(double? temperature, string convertTo)
Then you could check for null and return RedirectToAction:
if (temperature == null)
return RedirectToAction("ActionName", "ControllerName");
You'll also need to do the following to get the temperature value in your conversion methods:
temperature.Value
Hope this helps.

How do I store a comma-separated list in Orchard CMS?

Using Orchard CMS, I am dealing with a record and a part proxy, but cannot figure out how to save it into the DB. In fact, I confess I don't even know how to get the items I'm trying to save into this paradigm. I was originally using enum's for choices:
MyEmum.cs:
public enum Choices { Choice1, Choice2, Choice3, Choice4 }
MyRecord.cs:
public virtual string MyProperty { get; set; }
MyPart.cs:
public IEnumerable<string> MyProperty
{
get
{
if (String.IsNullOrWhiteSpace(Record.MyProperty)) return new string[] { };
return Record
.MyProperty
.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries)
.Select(r => r.Trim())
.Where(r => !String.IsNullOrEmpty(r));
}
set { Record.MyProperty = value == null ? null : String.Join(",", value); }
}
Now, in my service class, I tried something like:
public MyPart Create(MyPartRecord record)
{
MyPart part = Services.ContentManager.Create<MyPart>("My");
...
part.MyProperty = record.MyProperty; //getting error here
...
return part;
}
However, I am getting the following error: Cannot implicitly convert 'string' to System.Collections.Generic.IEnumerable<string>'
Essentially, I am trying to save choices from a checkboxlist (one or more selections) as a comma-separated list in the DB.
And this doesn't even get me over the problem of how do I use the enum. Any thoughts?
For some background:
I understand that the appropriate way to handle this relationship would be to create a separate table and use IList<MyEnum>. However, this is a simple list that I do not intend to manipulate with edits (in fact, no driver is used in this scenario as I handle this on the front-end with a controller and routes). I am just capturing data and redisplaying it in the Admin view for statistical/historical purposes. I may even consider getting rid of the Part (considering the following post: Bertrand's Blog Post.
It should be:
part.MyProperty = new[] {"foo", "bar"};
for example. The part's setter will store the value on the record's property as a comma-separated string, which will get persisted into the DB.
If you want to use enum values, you should use the Parse and ToString APIs that .NET provide on Enum.

Web API parameter filtering

This must be simple and I'm being incredibly dense but I can't find an example to help me figure it out. I want to filter my list of tblAsset items by their assessmentId which is passed in through a parameter. I'm able to get the parameter value ok, but I'm not sure how to write the query.
My model is built from an existing Database using the Model creation wizard.
Thanks for any help!
public IEnumerable<tblAsset> GettblAssets()
{
NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
var assessmentId = nvc["aid"];
//limit the assets by assessmentId somehow and return
}
You could use the .Where extension method on the IQueryable<tblAsset> instance returned by your database:
public IEnumerable<tblAsset> GettblAssets()
{
NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
var assessmentId = nvc["aid"];
// TODO: you might need to adjust the property names of your model accordingly
// Also if the assessmentId property is an integer on your model type
// you will need to parse the value you read from the request to an integer
// using the int.Parse method
return db.tblAsset.Where(a => a.assessmentId == assessmentId);
}

Resources