How to Display Exception In Grails? - grails

a have a problem with my code. how can i handle an error from service to my gsp? i tried it with render from service or controller, Validation error occured during call to save(): - Field error in object 'talent.CandidateProfile' on field 'core.db_email': rejected value []; codes with full exception trace. my sources:
def create() {
[candidateProfileInstance: new CandidateProfile(params)]
}
def save() {
def candidateProfileInstance = new CandidateProfile(params)
if (!candidateProfileInstance.save(flush: true)) {
render(view: "create", model: [candidateProfileInstance: candidateProfileInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'candidateProfile.label', default: 'CandidateProfile'), candidateProfileInstance.id])
redirect(action: "show", id: candidateProfileInstance.id)
}
My .gsp page code
<div class="full-filed">
<h3>Email Address:</h3>
</div>
<div class="fieldcontain ${hasErrors(bean: candidateProfileInstance, field: 'core.db_email', 'error')} ">
<label for="core.db_email" class="error_message"> <g:message
code="candidateProfile.core.db_email.label" default="Dbemail" />
</label>
</div>
<g:textField name="core.db_email" value="" class="loginTxtBox" placeholder="Email Address" />
i want just show to user an error, but not full exception trace

form your config.grooyPage
//grails.gorm.failOnError = true
just comment to this line...SO it will display your Custom Error

Related

g:select save to database selected item in grails

I have tables: Products and Shop.(I generate controllers using grails generate-all) Shop hasmany products
I'm trying to do is List all the shops in and save to database selected shop when creating a new product.
I listed all values using
<g:form controller="product" action="save" role="form">
<div class="form-horizontal" role="form">
<div class="form-group">
<label class="col-lg-3 control-label">Product Name:</label>
<div class="col-lg-8">
<g:textField name="productName" class="form-control" value="${product.productName}"/>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Product Barcode</label>
<div class="col-lg-8">
<g:textField name="date expired" class="form-control" value="${product.productBarcode}"></g:textField>
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Product Shop</label>
<g:select class="selectpicker" name="products.id" from="${tr.com.netiket.lkkstoreapp.Shop.list()}" value="shop?.products.id" optionValue="shopName"></g:select>
</div>
</g:form>
when i click create button it says
Property [shop] of class [class tr.com.nur.storeapp.Product] cannot be null
This bit doesn't look right:
<g:select class="selectpicker" name="products.id" from="${tr.com.netiket.lkkstoreapp.Shop.list()}" value="shop?.products.id" optionValue="shopName"></g:select>
The name should be the id of the Shop and the value should be the product's shop id, if present:
<g:select class="selectpicker" name="shop.id" from="${tr.com.netiket.lkkstoreapp.Shop.list()}" value="${product?.shop?.id}" optionValue="shopName"></g:select>
#Transactional
def save(Shop shop) {
//println "in shop save"
def currentUser=(User)springSecurityService.currentUser
shop.user=currentUser
shop.validate()
if (!shop) {
//println "I have no shop"
transactionStatus.setRollbackOnly()
notFound()
return
}
//if (shop.hasErrors()) {
if (shop.save(flush:true)) {
//println "shop has errors"
transactionStatus.setRollbackOnly()
respond shop.errors, view:'create'
shop.errors.allErrors
return
}
//shop.save flush:true
//println "shop has saved"
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'shop.label', default: 'Shop'), shop.id])
//println "redirecting"
redirect shop
}
'*' { respond shop, [status: CREATED] }
}
}
This is my save method. Actuaally I didint write anything here. Generate domain .

How to prevent data input for being erase in Grails with reCaptcha

I have gsp with two textfield for firstname-lastname and reCaptcha. What I want is for every wrong captcha code the user's input for firstname and last name won't be erased.
snippet for controller:
***captcha_code****
if (result) {
def person = new Person(params)
person.save()
render "Success!"
} else {
flash.message = message(code: 'forgotPassword.captcha.wrong')
redirect(controller:'person', action:'form')
}
snipper for form.gsp
***captcha_code_here***
<g:form controller="person" action="save">
<label>First Name: </label>
<g:textField name="firstName"/><br/>
<label>Last Name: </label>
<g:textField name="lastName"/><br/>
<g:if test="${flash.message}">
<div class="message" role="status" style="font-size: medium;color: green;">${flash.message}</div>
</g:if>
***captcha_code_here***
<g:actionSubmit value="Save"/>
To repopulate the fields you can use the same flash scope you're using for the message. On error, add the first and last name to the flash scope, and then in your GSP use those values when they are available:
PersonController
class PersonController {
def save() {
...
if(/* recaptcha failed */) {
flash.firstName = params.firstName
flash.lastName = params.lastName
}
...
}
}
GSP
<label>First Name: </label>
<g:textField name="firstName" value="${flash.firstName ?: ''}"/><br/>
<label>Last Name: </label>
<g:textField name="lastName" value="${flash.lastName ?: ''}"/><br/>
In Controller Action, send back fields that you want to be repopulated.

grails error message in an independent gsp view

In my grails project I've built up a new view in which user can perform a search of entities.
I've created the gsp adding the method search() in controller and automatically creating the gsp as described here
In this gsp there is only one input field and a g:actionSubmit button. If I fill form with correct data everything works well, but if data does not have any correspondance I would see an error message in the view like the validation error messages with popups...but I don't know how to show it, because I'm not using any bean with this gsp.
In addition, after an error, I would render the same view, but with render(view: "search", model: [patientInstance: patientInstance]) the view is the same, but path is /index and not /search...
How can I show an error message? How can I have the right path?
here is the search()
def search()
{
def patientInstance = new Patient()
if(params.patient_textField == "" || params.patient_textField == " " || params.patient_id =="")
{
//here I would like to show message
//the redirect works correctly
redirect(controller: "patient", action: "search")
}
else {
def patientToShow = Patient.findById(params.patient_id)
redirect(controller: "patient", action: "show", params: [id: patientToShow?.id])
}
}
here is the snippet of gsp
<g:form>
<div id="patientDiv">
<label for="patient">
<g:message code="event.patient.label" default="Patient" />
</label>
<input style=" margin: 0px 10px 10px 0px;" type="text" name="patient_textField" id="patient_textField" value="" placeholder="${g.message(code: 'patient.choose', default: 'Insert Patient...')}" />
<input type="hidden" id="patient_id" name="patient_id" value="" />
<g:actionSubmit class="search" value="${g.message(code: 'default.search.label', default: 'Search Patient')}" action="search" ></g:actionSubmit>
</div>
</g:form>
EDIT:
solved problem of path changing render with redirect(controller: "patient", action: "search")
In the error portion of your code you can do flash.error = "Your error message here"
And in the gsp do something like:
<g:if test="${flash.error}">
<div class="alert alert-info">
${flash.message}
</div>
</g:if>
There is already a flash bean in scope. http://grails.org/doc/latest/ref/Controllers/flash.html

Multipart post in grails causes 404 error

I try to upload data to a grails app. This works very good and the object is created in the database and the uploaded document is also present. Unfortunately i get a 404 error directly after the creation.
I am using grails 2.3.5 with the following code:
Action to save:
#Transactional
def save(Book bookInstance) {
if (bookInstance == null) {
notFound()
return
}
if (bookInstance.hasErrors()) {
respond bookInstance.errors, view:'create'
return
}
if(!bookInstance.id){
bookInstance.id = UUID.randomUUID().toString()
}
bookInstance.save flush:true
request.withFormat {
form {
flash.message = message(code: 'default.created.message', args: [message(code: 'Book.label', default: 'Book'), bookInstance.id])
redirect bookInstance
}
'*' {
respond bookInstance, [status: CREATED]
}
}
}
GSP:
<g:uploadForm action="save" class="form-horizontal">
<g:render template="form"/>
<div class="form-actions margin-top-medium">
<g:submitButton name="create" class="btn btn-primary" value="${message(code: 'default.button.create.label', default: 'Create')}" />
<button class="btn" type="reset"><g:message code="default.button.reset.label" default="Reset" /></button>
</div>
</g:uploadForm>
When the tag is used instead of the it works. The enctype="multipart/form-data" causes the error.
What can I try to solve this?
Thanks
You should check conf/Config.groovy and check that multipartForm: 'multipart/form-data', is present as a value for grails.mime.types, e.g.:
grails.mime.types = [
...
form: 'application/x-www-form-urlencoded',
multipartForm: 'multipart/form-data',
]
You also need to specify that it's a multipart form in your withFormat declaration:
request.withFormat {
form multipartForm
You can try 'render' or 'forward' instead of "respond" .

Grails empty entry into the database

I have been struggling with trying to create/save multiple instances at once in Grails, now I am almost there with the following code but when I hit save an empty row of options is created, can anyone help me with this
please see these two questions to see what I want to achieve
How to save multiple object from one view using Grails
Grails one to many relationship view
<g:textField name="question" value="${multipleChoiceQuestionInstance?.question}"/><br/>
<div class="fieldcontain ${hasErrors(bean: multipleChoiceQuestionInstance, field: 'options', 'error')} ">
<label for="options">
<g:message code="multipleChoiceQuestion.options.label" default="Options" />
</label>
<ul class="one-to-many">
<g:set var="counter" value="${0}" />
<g:each status="i" in="${multipleChoiceQuestionInstance?.options?}" var="o">
<li>
<g:textField controller="multipleChoiceOption" name="options[${i}].answerOption" action="show" id="${o.id}" value="${o?.encodeAsHTML()}"/>
<g:checkBox name="options[${i}].correctOption" value="${o.correctOption}"/><br/>
</li>
<g:set var="counter" value="${++counter}" />
</g:each>
<li>
<g:textField name="options[${++counter}].answerOption" value=""/>
<g:checkBox name="options[${counter}].correctOption" /><br/>
</li>
<li class="add">
<g:link controller="multipleChoiceOption" action="create" params="['multipleChoiceQuestion.id': multipleChoiceQuestionInstance?.id]">${message(code: 'default.add.label', args: [message(code: 'multipleChoiceOption.label', default: 'MultipleChoiceOption')])}</g:link>
</li>
</ul>
</div>
If you prefer not to click on the link here are the domain classes
Class MultipleChoiceQuestion {
String question
static constraints = {
...
}
static hasMany = [options:MultipleChoiceOption]
class MultipleChoiceOption{
String answerOption
boolean correctOption
MultipleChoiceQuestion question
static constraints = {
...
}
}
}
I am using automatically generated code by grails for the controller, it is as bellow
def create() {
[multipleChoiceQuestionInstance: new MultipleChoiceQuestion(params)]
}
def save() {
println params
def multipleChoiceQuestionInstance = new MultipleChoiceQuestion(params)
if (!multipleChoiceQuestionInstance.save(flush: true)) {
render(view: "create", model: [multipleChoiceQuestionInstance: multipleChoiceQuestionInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'multipleChoiceQuestion.label', default: 'MultipleChoiceQuestion'), multipleChoiceQuestionInstance.id])
redirect(action: "show", id: multipleChoiceQuestionInstance.id)
}
def update() {
def multipleChoiceQuestionInstance = MultipleChoiceQuestion.get(params.id)
if (!multipleChoiceQuestionInstance) {
.... //deleted for real estate
return
}
if (params.version) {
//version checking stuff
}
}
multipleChoiceQuestionInstance.properties = params
if (!multipleChoiceQuestionInstance.save(flush: true)) {
render(view: "edit", model: [multipleChoiceQuestionInstance: multipleChoiceQuestionInstance])
return
}
flash.message = message(code: 'default.updated.message', args: [message(code: 'multipleChoiceQuestion.label', default: 'MultipleChoiceQuestion'), multipleChoiceQuestionInstance.id])
redirect(action: "show", id: multipleChoiceQuestionInstance.id)
}
The reason that you are getting an empty row of options is because you are leaving a textfield with name option[counter] blank. This empty value is passed as a parameter to the controller action and it creates a new row with these blank values.
You should remove any blank options before calling
multipleChoiceQuestionInstance.properties = params
You can use something like this :
def emptyOptions = params.options.findAll{!it.answerOption}
params.options.removeAll(emptyOptions)

Resources