When running PUT method on Grails application system inserts new record instead of updating

Asked

Viewed 164 times

1

When trying to run JSON below via PUT method in a Grails application the system inserts a new record.

Urlmappings.groovy

class UrlMappings {

static mappings = {
    "/$controller/$action?/$id?(.$format)?"{
        constraints {
            // apply constraints here
        }
    }

    "/"(controller:"main")
    "500"(view:'/error')

    "/api/Patrimonio"(controller:"Patrimonio"){
        action = [GET:"showJSON", POST:"saveJSON", PUT:"updateJSON"]
    }

    "/api/Patrimonio/$id"(controller:"Patrimonio"){
        action = [GET:"showJSON", PUT:"updateJSON"]
    }

    "/api/Departamento"(controller:"Departamento"){
        action = [GET:"showJSON", POST:"saveJSON"]
    }

    "/api/Departamento/$id"(controller:"Departamento"){
        action = [GET:"showJSON", PUT:"updateJSON"]
    }

    "/api/Local"(controller:"Local"){
        action = [GET:"showJSON"]
    }

    "/api/Responsavel"(controller:"Responsavel"){
        action = [GET:"showJSON"]
    }

}
}

Departamentocontroller.groovy

package br.ufscar.dc.dsw

import static org.springframework.http.HttpStatus.*

import javax.persistence.criteria.CriteriaQuery;

import grails.converters.JSON
import grails.transaction.Transactional

import org.apache.tools.ant.types.resources.Restrict;
import org.hibernate.Criteria;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.springframework.security.access.annotation.Secured

import br.ufscar.dc.dsw.util.Constantes

@Secured(['ROLE_MEMBRO_COMISSAO', 'ROLE_SERVIDOR', 'IS_AUTHENTICATED_ANONYMOUSLY'])
@Transactional(readOnly = true)
class DepartamentoController {

    static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
    def registros

    def index() {
        params.max = Math.min(params.max ? params.int('max') : Constantes.MINIMO_PAGINACAO, Constantes.MAXIMO_PAGINACAO)
        registros = Departamento.createCriteria().list(params) {
            if (params.query) {
                if(params.tipo == "Sigla")
                    ilike("sigla", "%${params.query}%")
                else
                    ilike("nome", "%${params.query}%")
            }
        }
        respond registros, model:[departamentoInstanceTotal: registros.totalCount]
    }

    @Secured([
        'ROLE_MEMBRO_COMISSAO',
        'ROLE_SERVIDOR'
    ])
    def show(Departamento departamentoInstance) {
        respond departamentoInstance
    }

    @Secured('ROLE_MEMBRO_COMISSAO')
    def create() {
        respond new Departamento(params)
    }

    @Secured('ROLE_MEMBRO_COMISSAO')
    @Transactional
    def save(Departamento departamentoInstance) {
        if (departamentoInstance == null) {
            notFound()
            return
        }

        if (departamentoInstance.hasErrors()) {
            respond departamentoInstance.errors, view:'create'
            return
        }

        departamentoInstance.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.created.message', args: [
                    message(code: 'departamento.label', default: 'Departamento'),
                    departamentoInstance.id
                ])
                redirect departamentoInstance
            }
            '*' {
                respond departamentoInstance, [status: CREATED]
            }
        }
    }

    @Secured('ROLE_MEMBRO_COMISSAO')
    def edit(Departamento departamentoInstance) {
        respond departamentoInstance
    }

    @Secured('ROLE_MEMBRO_COMISSAO')
    @Transactional
    def update(Departamento departamentoInstance) {
        if (departamentoInstance == null) {
            notFound()
            return
        }

        if (departamentoInstance.hasErrors()) {
            respond departamentoInstance.errors, view:'edit'
            return
        }

        departamentoInstance.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.updated.message', args: [
                    message(code: 'Departamento.label', default: 'Departamento'),
                    departamentoInstance.id
                ])
                redirect departamentoInstance
            }
            '*'{
                respond departamentoInstance, [status: OK]
            }
        }
    }

    @Secured('ROLE_MEMBRO_COMISSAO')
    @Transactional
    def delete(Departamento departamentoInstance) {

        if (departamentoInstance == null) {
            notFound()
            return
        }

        departamentoInstance.delete flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.deleted.message', args: [
                    message(code: 'Departamento.label', default: 'Departamento'),
                    departamentoInstance.id
                ])
                redirect action:"index", method:"GET"
            }
            '*'{ render status: NO_CONTENT }
        }
    }

    protected void notFound() {
        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.not.found.message', args: [
                    message(code: 'departamento.label', default: 'Departamento'),
                    params.id
                ])
                redirect action: "index", method: "GET"
            }
            '*'{ render status: NOT_FOUND }
        }
    }

    def exportar = {
        chain(controller:'jasper',action:'index',model:[data:registros],params:params)
    }

    @Secured([
        'IS_AUTHENTICATED_ANONYMOUSLY'
    ])
    def showJSON(Departamento patrimonioInstance) {
        if(params.id && Departamento.exists(params.id)){
            render Departamento.findById(params.id) as JSON
        }else{
            render Departamento.list() as JSON
        }
    }

    @Transactional
    @Secured([
        'IS_AUTHENTICATED_ANONYMOUSLY'
    ])
    def saveJSON() {
        if (request.JSON != null) {
            def jsonObject = request.JSON
            def departamento = new Departamento(jsonObject)
            save(departamento)
        }
        render status: OK
    }

    @Transactional
    @Secured([
        'IS_AUTHENTICATED_ANONYMOUSLY'
    ])
    def updateJSON() {
        if (request.JSON != null) {
            def jsonObject = request.JSON
            def departamento = new Departamento(jsonObject)
            update(departamento)
        }
    }
}

JSON Enviado

{"nome":"TESTE", "sigla":"TE"}

I sent this JSON via PUT method at the address http://localhost:8080/Patrimonio/api/Departamento/6 only that instead of updating the code record 6 it inserts a new record. Via debug of the Grails application I saw that it is correctly calling the updateJSON method, however it does not update the record...

I’m using Grails 2.4.2

  • It is inserting, because within the updateJSON() you are creating a department and passing it to the update(). In update there is a save on this object. From what I understand of your problem, in the updateJSON you must recover an existing Department object and not create a new one.

  • Thanks for the answer, but the update method is correct. When I call it by the application the record is changed normally, the problem is when I call the updateJSON method. From what I saw, he’s entering the log because I wasn’t sending the ID. I made a new json by adding the id attribute, but it still gets NULL when creating the object through json....

  • Exactly @Thiago, when you call the update() of the application, you pass an instance of Department that already exists, you probably use a get or a findBy to find it in the bank. The problem is that updateJSON does not deliver an existing instance for the update. It creates a new instance and switches to the update. The save method, in turn, will enter a record. Try to put something like this on updateJSON: def department = Department.get(jsonObject.id) where jsonObject.id must be the id of an existing Department.

  • hmm got it. I did fetch the record, however how do I set the updated Json values in the object??

1 answer

1


The record is being entered, because within the action updateJSON a new department instance is being created and passed as a parameter to the method update. The method update, in turn, save this instance. Since it does not exist, then a new record is inserted into the database.

To solve, you need to get the instance you want to update in updateJSON, for this, it is necessary to use some of the database search methods provided by Grails (get, findBy, hql, criteria). Below is an example of how this could be done using get:

def updateJSON() {
    if (request.JSON != null) {
        def jsonObject = request.JSON
        def departamento = Departamento.get(jsonObject.id)
        departamento.properties = jsonObject
        update(departamento)
    }
}

In the above code, an instance is being obtained using the method get passing as parameter the Department ID. Once this is done, a Groovy way is used (department.properties = jsonObject) update attributes of an object.

Note that for this to work the fields in the jsonObject map must have the same name as the attributes of the Department class.

Another option to update attributes is to use the method bindData, available in the Controllers.

Take an example:

def updateJSON() {
    if (request.JSON != null) {
        def jsonObject = request.JSON
        def departamento = Departamento.get(jsonObject.id)
        bindData(departamento, jsonObject)
        update(departamento)
    }
}

Documentation: http://grails.github.io/grails-doc/latest/ref/Controllers/bindData.html

Browser other questions tagged

You are not signed in. Login or sign up in order to post.