Grails , how do I get an object NOT to save
Asked Answered
N

5

11

I am new to grails and trying to create a form which allows a user to change the email address associated with his/her account for a site I am creating.

It asks for the user for their current password and also for the new email address they want to use. If the user enters the wrong password or an invalid email address then it should reject them with an appropriate error message.

Now the email validation can be done through constraints in grails, but the password change has to match their current password. I have implemented this check as a method on a service class.

See code below:

def saveEmail =
{
    def client = ClientUser.get(session.clientUserID)
    client.email = params.email
    if(clientUserService.checkPassword(session.clientUserID , params.password) ==false)
    {
        flash.message = "Incorrect Password"
        client.discard()
        redirect(action:'changeEmail')
    }    
    else if(!client.validate())
    {
         flash.message = "Invalid Email Address"
         redirect(action:'changeEmail')
    }
    else
    {
        client.save();
        session.clientUserID = null;
        flash.message = "Your email address has been changed, please login again"
        redirect(controller: 'clientLogin' , action:'index')
    }
}

Now what I noticed that was odd was that if I entered an invalid email then it would not save the changes (as expected) BUT if I entered the wrong password and a valid email then it would save the changes and even write them back into the database even though it would give the correct "invalid password" error message.

I was puzzled so set break points in all the if/else if/else blocks and found that it was hitting the first if statement as expected and not hitting the others , so it would never come accross a call to the save() method, yet it was saved anyway.

After a little research I came accross documentation for the discard() method which you can see used in the code above. So I added this but still no avail. I even tried using discard then reloading the client object from the DB again but still no dice.

This is very frustrating and I would be grateful for any help, since I think that this should surely not be a complicated requirement!

Net answered 25/5, 2010 at 21:0 Comment(2)
client.discard() should be the way to do it, can you reproduce the problem in an integration test? What version of Grails are you using?Foti
I have just tried an integration test on the code, oddly enough it seemed to behave as I wanted but when I did it normally through the web I got the same problem again. I'd post my test code but I can't figure out how to do that here , it tells me that it is too many charsNet
W
10

Grails closes your Hibernate session at the end of the web request, which will flush out the changed object. The object's connected to your Hibernate session because you got hold of it via Hibernate (get()). If you want to avoid having the change flushed, you need to use discard().

This is done automatically by a failing validator, which is why you're not having to do it for a validation fail.

You'd simplify the code, however, by either moving this logic to a custom validator on one of your ClientUser fields, which would automatically discard the object on failure, or by using a Grails command object, which could also encapsulate the verification logic. Then you'd just check for errors on the command object.

Weaver answered 25/5, 2010 at 23:36 Comment(2)
yes, but that is what is puzzeling me , I am using discard and this is working on the integration test but not on the webNet
Remember, integration tests roll back your transaction at the end. At the web, your transaction will eventually commit.Weaver
H
6

Using get() method retrieve data in read-write mode, so if you change anything it will be persist.Use read() method that can retrieve data in read-only mode so if you change anything then need to use save() method.That will resolve your problem.

Take a look at this http://grails.org/doc/latest/guide/GORM.html#basicCRUD

Habituate answered 24/3, 2014 at 4:38 Comment(1)
this works for me though I don't understand why discard does not work if you use get, thanks anywayInstigation
W
2

Use read method that retrieves an instance of the domain class for the specified id in a read-only state.

See the Grails documentation about read.

Wincer answered 19/7, 2012 at 10:59 Comment(0)
B
0

You are just doing flash which has nothing to do with rolling back transaction. In the event of error throw RuntimeException and it will roll back your changes to the database.

Bailiwick answered 21/7, 2011 at 13:45 Comment(0)
S
0

After an R & D, I figure out that we need to clear a whole session like:

session.clear()

According to the documentation :

Completely clear the session. Evict all loaded instances and cancel all pending saves, updates and deletions. Do not close open iterators or instances of ScrollableResults.

We need to properly cleanup the hibernate session. In result the session is return to usable state and for future use it will not impact by the earlier error.

Sorensen answered 18/12, 2015 at 7:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.