[groovy-user] How should I update a domain class object in a RESTful application?

21 views
Skip to first unread message

Enrique Medina Montenegro

unread,
Aug 1, 2008, 11:30:16 AM8/1/08
to us...@groovy.codehaus.org, us...@grails.codehaus.org
Hi folks,

I know that this question is more a Grails one, but as I haven't seen much movement lately in the Grails mail list, I thought it could be fine to post it here, as there may be many Groovy users which are Grails users as well.

I'm building a RESTful application in Grails, which basically serves information consumed by PHP clients. Given the following flow:

1) PHP sends a GET to /country/2, to get a specific country with ID = 2
2) Grails gets the request, maps it to the show method in the controller, and then returns an XML representation of the Country domain class with ID = 2 (let's assume for the sake of simplicity that it's just a class with ID (autogenerated) and name)
3) The resulting XML is send back to PHP, which uses it to show the info to the user
4) Now the user modifies the name of the country, and clicks update
5) PHP sends a PUT request to /country/2, with an XML that provides the new name for the specific Country with ID = 2
6) Grails gets the request, maps it to the update method in the controller, and here comes my issue.

As these are two completely different, separated web apps (PHP & Grails), when I get the params in Grails about the XML sent by PHP with the PUT request, what should I do to update the object?

I've tried to create a new country, using the "params.country" as a parameter to the constructor, so a new country is created, but then the ID is not assigned whatsoever. Next, I assign it manually (newCountry.id = params.id), but when I call newCountry.merge(), it ends up inserting a completely new record in the DB, as opposite to updating my existing country as expected.

Then, I took a look at how RoR solves this issue, and in this case, it firstly loads the country by ID, and then calls "update_attributes", passing as an argument the "params.country". Apparently, this method detects changes in the attributes, so when you merge the object back, everything is fine.

As I haven't found such a similar behaviour in Grails, I've been forced to define a "updateAttributes" for each and every of my domain classes, so I was wondering whether there's a more generic way to attack this limitation.

Thanks in advance.

Regards,
Enrique Medina.

Graeme Rocher

unread,
Aug 1, 2008, 11:49:55 AM8/1/08
to us...@groovy.codehaus.org, us...@grails.codehaus.org
On Fri, Aug 1, 2008 at 4:30 PM, Enrique Medina Montenegro
<e.med...@gmail.com> wrote:
> Hi folks,
>
> I know that this question is more a Grails one, but as I haven't seen much
> movement lately in the Grails mail list, I thought it could be fine to post
> it here, as there may be many Groovy users which are Grails users as well.

Hmm, no movement on the Grails list? There is around 50 posts on there
per day.. what would you class as movement?

>
> I'm building a RESTful application in Grails, which basically serves
> information consumed by PHP clients. Given the following flow:
>
> 1) PHP sends a GET to /country/2, to get a specific country with ID = 2
> 2) Grails gets the request, maps it to the show method in the controller,
> and then returns an XML representation of the Country domain class with ID =
> 2 (let's assume for the sake of simplicity that it's just a class with ID
> (autogenerated) and name)
> 3) The resulting XML is send back to PHP, which uses it to show the info to
> the user
> 4) Now the user modifies the name of the country, and clicks update
> 5) PHP sends a PUT request to /country/2, with an XML that provides the new
> name for the specific Country with ID = 2
> 6) Grails gets the request, maps it to the update method in the controller,
> and here comes my issue.
>
> As these are two completely different, separated web apps (PHP & Grails),
> when I get the params in Grails about the XML sent by PHP with the PUT
> request, what should I do to update the object?
>
> I've tried to create a new country, using the "params.country" as a
> parameter to the constructor, so a new country is created, but then the ID
> is not assigned whatsoever. Next, I assign it manually (newCountry.id =
> params.id), but when I call newCountry.merge(), it ends up inserting a
> completely new record in the DB, as opposite to updating my existing country
> as expected.

Why are you calling merge() which is for detached instances. Have you
tried save()?

If it is still a problem raise an issue with an example of what you
are trying to achieve

Cheers


>
> Then, I took a look at how RoR solves this issue, and in this case, it
> firstly loads the country by ID, and then calls "update_attributes", passing
> as an argument the "params.country". Apparently, this method detects changes
> in the attributes, so when you merge the object back, everything is fine.
>
> As I haven't found such a similar behaviour in Grails, I've been forced to
> define a "updateAttributes" for each and every of my domain classes, so I
> was wondering whether there's a more generic way to attack this limitation.
>
> Thanks in advance.
>
> Regards,
> Enrique Medina.
>

--
Graeme Rocher
Grails Project Lead
G2One, Inc. Chief Technology Officer
http://www.g2one.com

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


Enrique Medina Montenegro

unread,
Aug 1, 2008, 12:07:12 PM8/1/08
to us...@groovy.codehaus.org, us...@grails.codehaus.org
Graeme,

I didn't want to bother you, but as I was not getting any emails from the list, I thought it was not moving... but it's probably my fault (config issue).

Anyway, I tried what you suggested, but still getting errors:

INPUT:
======
<countryVO>
  <name>United States</name>
</countryVO>

REQUEST:
=========
PUT /country/4/

URL/METHOD MAPPING:
=====================

    def update =
    {
        if (params.id)
        {
            def p = new CountryVO(params['countryVO'])
            p.id = params.id
       
            if (p.save())
            {
                render p as XML
            }
            else
            {
                // render error message
            }
        }
    }

However, there's some weird behaviour still here. I can see that the update is done:

Hibernate: /* update es.delega.restful.dominio.vo.CountryVO */ update COUNTRIES set  NAME=?, VERSION=? where COUNTRY_ID=? and VERSION=?

But I get an OptimisticLockException, where the ID is somehow bizarre, as it has nothing to do with the one I used in the PUT request --> params.id = 4

[9109] errors.GrailsExceptionResolver Object of class [es.delega.restful.dominio.vo.COuntryVO] with identifier [52]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [es.delega.restful.dominio.vo.CountryVO#52]
org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Object of class [es.delega.restful.dominio.vo.CountryVO] with identifier [52]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [es.delega.restful.dominio.vo.CountryVO#52]
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:654)
    at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
    at org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor.postHandle(OpenSessionInViewInterceptor.java:184)
    at org.codehaus.groovy.grails.orm.hibernate.support.GrailsOpenSessionInViewInterceptor.postHandle(GrailsOpenSessionInViewInterceptor.java:59)

Any clue?

Thanks.
--
Salu2,
Quique.

Graeme Rocher

unread,
Aug 1, 2008, 12:32:14 PM8/1/08
to us...@grails.codehaus.org, us...@groovy.codehaus.org
Well the one thing I will say is that I understand why its doing an
insert because you're creating a new instance. You should use the
static get method to get the existing instance:


def p = new CountryVO.get(params.id)
p.properties = params['countryVO']

Cheers


On Fri, Aug 1, 2008 at 5:07 PM, Enrique Medina Montenegro

Enrique Medina Montenegro

unread,
Aug 1, 2008, 12:45:57 PM8/1/08
to us...@groovy.codehaus.org, us...@grails.codehaus.org
Cool! That p.properties is what I was looking for.

Thanks!
--
Salu2,
Quique.
Reply all
Reply to author
Forward
0 new messages