Grails `respond` returns null - grails

I want to send validation errors back to a different page (add), so I have this for my save action:
#Transactional(readOnly = false)
def save(AddDomainCommand command) {
if (command.validate() && session.isLoggedIn && session.publisher) {
// do some stuff
return redirect(controller: 'Widget', action: 'generate')
}
log.info("Validation failed for $command")
respond view: "add", model: [domain: command]
}
It errors with javax.servlet.ServletException: Could not resolve view with name 'save' in servlet with name 'grailsDispatcherServlet'
If I print the response from respond, I get null! So that explains why it's going to save, because that's the convention for the action's name.
I need it to go back to the view it came from (add.gsp), yet grails respond is null and thus defaulting to save.gsp.
Any ideas?

respond uses a different syntax and is used when you want to be able to support multiple client types based on mime type, e.g. JSON and/or XML for a REST client and HTML/GSP for a regular browser client. If you just want to use add.gsp to render HTML, use render:
render view: 'add', model: [domain: command]

Related

Grails - Send List of objects in params of redirect

My problem is that i want to preview data on index view without saving data in database. For this purpose, I want to send the list of objects in params section of redirect. And on receiving action want to use that list of objects.But when i include as below
def preview(){
//some code
redirect action: "index", params:[planId:params.planId, beamsInfoList: beamsInfoList]
}
I want something like below to happen.
def index() {
//some code
try{
planInfo.beamInfo = (params.beamsInfoList==null)?planInfo.beamInfo:params.beamsInfoList //beamInfo is also list
//some code
Object[] obj = GRMUtils.calculateTotalBeamsPower(planInfo.beamInfo)
totalPlanPower = (Float)obj[0];
beamPowerMap= (Map<Integer, String>)obj[1];
AmMapUtility utility=new AmMapUtility()
output = utility.generateAMmapFromBeams(planInfo.beamInfo, GRMConstants.POWER_MAP_PAGE);
if(null==output){
flash.error = message(code: 'beammap.noinfoerror.message')
}
}catch(Exception e){
log.error "Excepton occured while loading Power Map", e
}
respond beams, model:[centerLong:output.getCenterLongitude(),centerLat:output.getCenterLatitude(),amMapImageProperty:output.getMapImages(),
amMapLinesProperty:output.getMapLines(), planId:params.planId, planInfo:planInfo, powersControlCarrier: powersControlCarrier, powersTrafficCarrier:powersTrafficCarrier,satPower: planInfo.satellite.satelliteMaxPower, totalPlanPower: totalPlanPower, gatewayPower: planInfo.gateway.gatewayAggregateEIRP,fesOutputPowerLimit:fesOutputPowerLimit, beamPowerMap: beamPowerMap,powerRangeColorMap:output.getReuseColorMap()]
}
It does not redirect to index method and not showing any errors. Both actions are in same controller. I have used flash, but its not helping either as value reflected on second request. I have tried session too, but i am getting error
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
on some DB fetch. I am stuck. I am new to grails and groovy. Please help.
Edit: i have found my list is large, that is why its not redirecting. Please help me with another alternative like how can i use request attribute if it is possible?
I think i have solved the problem. Its working now. All i need to do is to use the request setattribute as
request.beams = beams
And no need to pass the list in params of redirect, which i was earlier used to do. Instead of using redirect, i used forward as below:
request.beams = beams
forward action: "index", params:[planId:params.planId]

how to pass control to grails error page if the exception occurs in controller?

I have one method in controller which will be called when user clicks on link
<g:link controller="reporting" action="dataCenterNetworkReports">
<g:message code="reports.data.center.network"/>
</g:link>
that method will be getting response from the webservice. Now my question is if some thing goes wrog in WS and returns an error I need to pass the control and display the error message. how to display common error page when some thing goes wrong and comes to catch block.
Grails have the default error gsp in views/error.gsp. If you look the code this needs an exception, so something like this I think should be enough (not tested):
Your controller method
def dataCenterNetworkReports() {
String view = "myDefaultView"
def model = [:]
try {
//call webservice
}catch(e) {
view = '/error'
model.exception = e
}
//when occur some exception view will be /error
render(view: view, model: model)
}
But if you need to show some custom layout, then flash object can be your choice.

How to handle grails exceptions in an ajax request?

If I am making a regular request I can define handling of errors and exceptions in UrlMappings.groovy as in the following example:
"403"(controller: 'error', action: 'index', params:['code':'403'])
"404"(controller: 'error', action: 'index', params:['code':'404'])
"500"(controller: 'error', action: 'index', params:['code':'500'])
"500"(controller: 'home', action: 'noPrivileges', exception: IllegalOperationException)
I can then handle the errors in a specific controller and render a view of my choice e.g.
class ErrorController {
def index = {
render view: "/errors/myErrorPage", model: [code: params.code]
}
}
This works perfectly and whenever there is an error on server I get my error page.
Now how can I achieve the very same behavior for ajax requests? I am making ajax requests either with grails remoteFunction or formRemote. Everytime when an exception occurs on the server, I want to execute the same piece of code in javascript (e.g. I want to show an alert with alert('There was an exception')).
The above described approach does not work for ajax requests. I still get back an error and even though there is content of myErrorPage.gsp in the error, it is not printed into the html element which I specified with update parameter of formRemote or remoteFunction.
I finally found a perfectly clean solution compatible with the approach which is used for handling standard requests.
You need to modify action which is handling the error as in the following example:
class ErrorController {
def index = {
if (request.xhr) {
response.status = 200
render template: "/errors/myAjaxErrorTemplate", model: [code: params.code]
} else {
render view: "/errors/myErrorPage", model: [code: params.code]
}
}
}
With request.xhr you can differentiate between ajax request and a standard request. In ajax request you further need to tell grails that the response is OK with setting response status to 200.
Very nice and clean. :) I am surprised this can't be googled anywhere...
The remoteFunction trigger a couple of events onFailure and on_ERROR_CODE. You can use that events to show your warning messages.
You can see more details in docs
If the request status is set correctly you could define an JavaScript function via the onFailure attribute of remoteFunction/formRemote.
Within this function you could handle your exception on client side.
Using the sample from the docs it could look like this:
<select onchange="${remoteFunction(action: 'bookByName',
update: [success: 'great', failure: 'ohno'],
params: '\'bookName=\' + this.value'),
onFailure: 'handleError'}">
<option>first</option>
<option>second</option>
</select>

Redirection in Grails Web-flow

I have question regarding redirection in Grails web-flow.
I am in a view state which will allow users to enter the answers for a question. On 2 wrong attempts I should be able to re-direct the user to view page from different controller. What i mean is
challengeQuestionOne{
onRender() {
//Display question
}
on('next') {BuildQuestion command ->
bindData(flow.recovery,command)
[return the model to flow]
if(command.hasErrors()) {
flow.command = command
return error()
}
if(check for status. If doesnot pass){
flash.message=message(code:'loginForm.account.locked', default: 'Please Contact Admin.')
redirect(controller : "login",action: "login")//how to redirect from here to diff controller
}
if (//compare answer entered) {
}
else{
//set status not active
}
}.to("challengeQuestionTwo")
on(Exception).to("error")
on('cancel').to('finish')
}
I have tried to redirect from onRender . It was redirecting to the page. But how do I display the error msg on the redirected page. How can i forward the error message from one controller to other??
Ivo Houbrechts wrote an excelent tutorial about grails webflow:
Webflow defines its own flash scope. Although it has the same semantics as the standard grails flash scope (the main purpose is to store objects only until after the next request), it is a different scope. This means that objects stored in webflow's flash scope are not visible in standard grails actions.
import org.springframework.web.context.request.RequestContextHolder
....
RequestContextHolder.currentRequestAttributes().flashScope.message = "YourMessage"
You can read more here:
http://livesnippets.cloudfoundry.com/docs/guide/
Flash scope will not work in this case as expected.
Try to use another approach to show error. E.g. you can pass parameters with redirect. Or you can throw some exception and check it on rendered page as follow:
<g:if test="${flowExecutionException}">
<div class="error"><g:message code="loginForm.account.locked"/></div>
</g:if>

Grails "loses" custom URL mapping when following any links on the page

I have an application where users can browse maps in two ways (like thumbnails and in a list)
/map/browse
/map/list
Now, I would like to restrict these views to just show maps of a specific user, for example through
/user/3/browse
/user/3/list
So I created the mapping:
"/user/$userId/browse" {
controller = "map"
action = "browse"
}
"/user/$userId/list" {
controller = "map"
action = "list"
}
Now, I can go to /user/3/browse, but as soon as I click on a pagination link or change the pagination filters, the URL goes back to /map/browse.
Also, if I set the userId to null in the controller, I get the error:
Error 500: Error processing GroovyPageView: Error executing tag : Unable to create URL for mapping [/user/(*)/list] and parameters [["action":"list", "controller":"map", "max":20, "offset":0, "sort":"uploadDate", "order":"desc", "userId":null, "totalMaps":30]]. Parameter [userId] is required, but was not specified! at /views/map/browse.gsp:26
The pagination works as follows:
<div class="paginateButtons">
<g:paginate controller="map" action="browse" total="${mapInstanceTotal}"></g:paginate>
</div>
What can I do against that or what would be the correct way of implementing what I want?
I don't necessarily need to have that URL mapping, I only need a nice way of saying: "Display maps of only one user"
It seems that the problem is not at your URL mapping configuration ,but in your way to create link. I think it's better if you use Named URL Mapping : it's clearer than your approach now, and when create link for pagination you only need to specify the url name. For example:
In UrlMappings.groovy:
static mappings = {
name accountDetails: "/details/$acctNumber" {
controller = 'product'
action = 'accountDetails'
}
}
In view - gsp page:
<g:link mapping="accountDetails" params="[acctNumber:'8675309']">
Show Account
</g:link>

Resources