Refatorando código de validação em um controller
12/09/2016 12:29
0
Bom dia a todos,

Segue o controller abaixo com o método update que escrevi:
class OperacaoController {

static scaffold = Operacao

OperacaoService operacaoService

(...)
def update() {

  Operacao operacaoInstance = Operacao.get(params.id)
  bindData(operacaoInstance, params)
 
 // Validação 1
  if (params?.dataFimVigencia) {
if(params?.dataInicioVigencia > params?.dataFimVigencia) {
operacaoInstance.errors.rejectValue('', 'dataInicioVigencia.posterior.dataFimVigencia', [
params.dataInicioVigencia] as String[], "")
render(view: 'edit', model: [operacaoInstance: operacaoInstance])
return
}
  }

 // Validação 2
  if (!operacaoInstance) {
flash.message = message(code: 'default.not.found.message', args: [
  message(code: '{domainClass.propertyName}.label', default: 'Operacao'),
  params.id
])
redirect(action: "list")
return
  }
 
 // Validação 3
  if (operacaoService.isOperacaoUnique(operacaoInstance)) {
if (operacaoInstance.save(flush: true, failOnError: true)) {
flash.message = message(code: 'default.updated.message', args: [
message(code: '${domainClass.propertyName}.label', default: 'Operacao'),
operacaoInstance.id
])

redirect(action: "edit", id: operacaoInstance.id)
}
  } else {
operacaoInstance.errors.rejectValue('', 'default.not.unique.message', [
  'Nome', 'Operacao', params.nome] as String[], "")
render(view: 'edit', model: [operacaoInstance: operacaoInstance])
return
  }
}
}


Extraí a primeira validação no método validateDataAndRedirectIfIsInvalid conforme código abaixo:

class OperacaoController {

static scaffold = Operacao

OperacaoService operacaoService

(...)
def update() {

  Operacao operacaoInstance = Operacao.get(params.id)
  bindData(operacaoInstance, params)
 
 // Validação 1
  validateDataAndRedirectIfIsInvalid(operacaoInstance)

 // Validação 2
  if (!operacaoInstance) {
flash.message = message(code: 'default.not.found.message', args: [
  message(code: '{domainClass.propertyName}.label', default: 'Operacao'),
  params.id
])
redirect(action: "list")
return
  }
 
 // Validação 3
  if (operacaoService.isOperacaoUnique(operacaoInstance)) {
if (operacaoInstance.save(flush: true, failOnError: true)) {
flash.message = message(code: 'default.updated.message', args: [
message(code: '${domainClass.propertyName}.label', default: 'Operacao'),
operacaoInstance.id
])

redirect(action: "edit", id: operacaoInstance.id)
}
  } else {
operacaoInstance.errors.rejectValue('', 'default.not.unique.message', [
  'Nome', 'Operacao', params.nome] as String[], "")
render(view: 'edit', model: [operacaoInstance: operacaoInstance])
return
  }
}

private validateDataAndRedirectIfIsInvalid(Operacao operacaoInstance) {
  if (params?.dataFimVigencia) {
if (params?.dataInicioVigencia > params?.dataFimVigencia) {
?operacaoInstance.errors.rejectValue('', 'dataInicioVigencia.posterior.dataFimVigencia', [
params.dataInicioVigencia] as String[], "")
render(view: 'edit', model: [operacaoInstance: operacaoInstance])
return
}
  }
}
(...)
}



O problema desse código é que a linha contendo o return do método validateDataAndRedirectIfIsInvalid não funciona, apesar de não apresentar erro.

O código segue o fluxo normal dentro do controller ignorando o return e consequentemente não mostrando a mensagem de erro e redirecionando.

Qual a melhor maneira de fazer esse refactoring ?
Tags: Grails, refactoring, controller, redirect, validation


0
Opa,

a melhor forma sem sombra de dúvidas é mover todo este seu código de validação para um serviço ou como uma constraint personalizada usando a função validator (http://docs.grails.org/latest/ref/Constraints/validator.html)

Até para facilitar a escrita dos seus testes.


0
Obrigado pelo retorno Henrique,

Mas e quanto ao tratamento das flash messages e redirects ?
Algumas validações possuem redirecionamentos outras renders e mensagens de erro/sucesso diferentes.  Eu lidaria isso dentro do service também ?


0
Oi James, não.

Seu serviço não deve sonhar que exista algo chamado controlador. Ele deve retornar um valor informando se foi executado com sucesso ou disparar um erro caso alguma das condições não seja satisfeita.

NO caso de disparar um erro, recomendo que você crie uma classe Exception que te forneça toda a informação necessária para que seu controlador saiba se deve ser feito um redirect, o que deve ser incluído no escopo flash, etc.



Ainda não faz parte da comunidade???

Para se registrar, clique aqui.


Aprenda Groovy e Grails com a Formação itexto!

Newsletter Semana Groovy

Assinar

Envie seu link!


Livro de Grails


/dev/All

Os melhores blogs de TI (e em português) em um único lugar!

 
Creative Commons
RSS Grails Brasil é mantido por itexto Consultoria.
Em caso de problemas contacte Henrique Lobo Weissmann (Kico) por e-mail: kico@itexto.com.br
Todo o conteúdo presente neste site adota o Creative Commons como licença padrão.
Ver: 4.14.0
itexto