I've created the following class
class ErrorsController {
def index = {
log.error request.exception
}
}
In my UrlMappings I have this:
"500"(controller: "errors")
"404"(controller: "errors")
request.exception is always null. Debugging, I see 2 parameters in the request object. controller and action. I see no exception. If I remove the "404", it works as expected. I'm using Grails 1.3.7.
Related
The getStarted action redirects to companyInfo action which renders companyInfo.gsp and immediately after the page rendering, companyInfo action getting called one more time. I don't understand what the problem is.
class MyController {
#Secured('ROLE_USER')
def getStarted(){
def renderParams = [view: 'getStarted', model: [:]]
if(request.method != 'POST') {
render(view: 'getStarted')
} else {
def company = new Company()
.......
redirect(action: 'companyInfo', params: [id: company.id])
}
}
#Secured('ROLE_USER')
def companyInfo() {
def renderParams = [view: 'companyInfo', model: [:]]
if (request.method != 'POST') {
renderParams.model.cmpId = params?.id
render(renderParams)
}
}
}
See this answer. Grails trys to map get* to properties. And when the controller is called grails tries to map getStarted to a property called started, calling the method. So, Never Use get**** as your action name
I've tried to create a custom 404 url mapping for URL's that are not found:
"/test" {
controller="test"
}
"404" {
controller="application"
action="send404"
}
"500" {
controller="application"
action="send500"
}
But for some reason, the controller and action are never called. I get the default container 404 page. So, instead I tried:
"/test" {
controller="test"
}
"/**" {
controller="application"
action="send404"
}
"500" {
controller="application"
action="send500"
}
Which seems to work fine, except that it also seems to call the send404 action on every request. For example, if I hit /test, I see the test page, but I also get the log statement I made in the send404() action.
Ideas appreciated...
Have you tried killing whitespace in your declaration, as outlined in this answer?
"404"(controller:'application', action:'send404')
There is also an open issue GRAILS-4232 about this topic.
In grails, there is an ErrorController, the one that render stacktrace on 500, etc.
class UrlMappings {
static mappings {
"403" (controller: "error", action: "forbidden")
"404" (controller: "error", action: "notFound")
"500" (controller: "error", action: "internalError")
}
}
And then, you can render(controller:"error", action"notFound") in another controller to stay RESTful. Or it will automagically render the notFound action of the error controller.
More details here : http://groovy.dzone.com/articles/grails-exception-handling-http
Perhaps it's favicon.ico that's being requested by the browser on each request that's causing this to happen.
// Route 404 to this action to see!
def send404() {
log.error("404 Page Not Found! " + request.forwardURI)
response.status = 404;
render(view:"/application/not-found.gsp")
}
I'm trying to pass an error message from a grails controller to a grails error controller in order to display an error message in the HTTP response, but I'm not sure what parameter is holding the error message in the error controller.
URLMappings.groovy
All 500 errors are mapped to ErrorsController
"500"(controller: "errors", action: "serverError")
GenericController
def {
try{
//do some work
}catch(Exception e){
response.sendError(500, e.getMessage())
}
}
ErrorsController
def serverError = {
render( how can I access the exception details here?? )
}
I need to access the exception in the ErrorsController so I can output it to the HTTP response.
The usual way to pass short informational messages between controllers is to place it in the flash scope. For example:
def myAction = {
try {
...
} catch (Exception e) {
flash.message = e.message
response.sendError(500)
}
}
In this particular case, though, why are you catching the exception? If you let the exception fall through, grails will automatically generate a server error and call the "500" mapping. In your error controller, the exception will be available as request.exception.
In your ErrorsController:
def serverError() {
render request.getAttribute('javax.servlet.error.message')
}
renders the message from e.getMessage().
What's the best way to handle invalid ids in a Grails controller action?
When MyDomainClass.get(params['i']) returns null in my controller action I want the user to see my custom 'Not Found' page and for a 404 HTTP response code to be returned - I can't figure out the cleanest way to do this.
Thanks.
I've used the following in my controllers, where 'notFound' is a custom 404 page:
def show = {
def referenceData = ReferenceData.get( params.id )
if (referenceData)
{ return [ referenceData : referenceData ] }
else
{ redirect(uri:'/notFound') }
}
I also mapped the custom error pages in UrlMapping.groovy, something like
static mappings = {
"403"(controller: "errors", action: "forbidden")
"404"(controller: "errors", action: "notFound")
"500"(controller: "errors", action: "serverError")
}
or
static mappings = {
"403"(view: "/errors/forbidden")
"404"(view: "/errors/notFound")
"500"(view: "/errors/serverError")
}
Grails Docs - mapping to response codes
EDIT - I apologize for misreading your question. the render method takes a status code. So in the controller, if nothing is found, try
render status: 404
or
render view: you_not_found_view
or both (in one render call).
Here's my magic formula for doing this. Maybe there's a better way, but this one works and ensures the same 404 view renders whether you generate the 404 or grails does it internally (no controller found, for example).
First, create a View class that extends AbstractView:
class NotFoundView extends AbstractView {
#Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response) {
response.sendError(HttpServletResponse.SC_NOT_FOUND)
}
}
Next, create an error controller:
class ErrorController {
def notFound = {
return render(view: '/error/notFound')
}
}
Now create your error view under views/error/notFound.gsp:
<g:applyLayout name="main">
<!doctype html>
<html>
<head>
<title>Oops! Not found!</title>
</head>
<body>
<h1>Not Found</h1>
<section id="page-body">
<p>Nothing was found at your URI!</p>
</section>
</body>
</html>
</g:applyLayout>
It's crucial that you use the <g:applyLayout> tag. If you use your layout will render twice and nest itself.
Now for the URL mapping:
"404"(controller: 'error', action: 'notFound')
You're all set now to send that 404 from your controller:
def myAction = {
Thing thing = Thing.get(params.id)
if (!thing) {
return new ModelAndView(new NotFoundView())
}
}
This approach also lets you easily log the 404, try to resolve it and send a 301, or whatever you want to do.
I'm trying to disable the Searchable plugin default search page (http://localhost/searchable/), but haven't found a way to do it. Anyone know how this can be done, preferably in a legit way, but resorting to trickery if necessary?
I usually re-route error code handlers to a controller so I can do some logging or whatever before rendering the view. You can use that here also:
class UrlMappings {
static mappings = {
"/searchable/$action?"(controller: "errors", action: "urlMapping")
"/$controller/$action?/$id?" { }
"/"(view:"/index")
"403"(controller: "errors", action: "accessDenied")
"404"(controller: "errors", action: "notFound")
"405"(controller: "errors", action: "notAllowed")
"500"(view: '/error')
}
}
where ErrorsController looks something like this:
class ErrorsController {
def accessDenied = {}
def notFound = {
log.debug "could not find $request.forwardURI"
}
def notAllowed = {}
def urlMapping = {
log.warn "unexpected call to URL-Mapped $request.forwardURI"
render view: 'notFound'
}
}
and you'll need to create accessDenied.gsp, notFound.gsp, and notAllowed.gsp in grails-app/errors
By sending a 'hidden' controller to its custom mapping you can log unexpected access to it, but still render the 404 page to hide its existence.