url mappings grails - grails

right, basically we have a link into our system that is all lowercase but that needs to be camel cased. rather than get the other developers to fix this, I want to just make the problem go away by url magic
"/myobj/$action?/$id?"{
controller: "myObj"
}
what i am trying to do is map anything that references controller myobj to controller myObj instead, and keep the action and everything else the same. The above code gives an exception, saying the
2010-07-11 18:14:50,021 ERROR [default] - Servlet.service() for servlet default threw exception
java.lang.IllegalArgumentException: URL mapping must either provide a controller or view name to map to!
however the following works
"/myobj/$action?/$id?"(controller: "myObj")
I dont understand, given the documentation. Why didnt the closure work? This is grails 1.2.0...

You should use
'/myobj/$action?/$id?' {
controller = 'myObj'
}
Edit
As a bit of explanation: the colon in the working example creates a map as described here (the working case is a Groovy function invocation with named parameters). Within the closure, you need to set the value of the controller property directly, i.e., using the equals sign.
This difference is demonstrated not specifically highlighted in the Grails URL mapping documentation.
Edit
Here's an untested method that may yield case insensitive controller mappings... maybe.
'$myController/$action?/$id?' {
grailsApplication.getArtefacts('Controller').find { it.name.toLowerCase() == myController.name.toLowerCase }.with { controller = it.name }
}
I'm assuming here (which I haven't verified) that the Grails application is available within the MappingCapturingClosure in the DefaultMappingUrlEvaluator.

Related

Can Grails Controller name have number in it

Can I have a grails controller named Office365Controller. More specifically is it allowed to have numbers in controller names? In url mapping i use office365 as controller. Could this be somehow conflicting with camel casing convention used for controller.
I ask this question because when i call a function inside this controller, i get tomcat error 403. My all other controllers are working fine and security for all of them is same.
Can I have a grails controller named Office365Controller.
Yes.
More specifically is it allowed to have numbers in controller names?
Yes.
I ask this question because when i call a function inside this
controller, i get tomcat error 403.
There may be some other factor in your app that is causing the issue, but I don't think the numbers in the controller name would cause a 403. A controller like this should work fine:
class Office365Controller {
def index() {
render retrieveSomeValue()
}
protected retrieveSomeValue() {
'hello world'
}
}
It isn't clear what might be going wrong in your app, but the answer to the questions quoted above is "yes".

Grails view URL Mapping

I'm kind of new to grails and I'm trying to just map a basic URL request to a view.
So, say I have a view, /x/index.gsp and I want the user to be able to go to it. There will also be /y/index.gsp, /z/index.gsp, etc.
I defined it like so:
"/$customer/index" { view = {params.customer+"/index"} }
This seems to throw an exception though. I also have :
"/$customer/$controller/$action?/$id?" { }
which does work and I don't want to have to create a controller that doesn't really do anything but handle the index call and show it.
I'm sure I'm missing something simple but I don't know what it is.
The reason the first mapping fails is because it can't figure out what controller to route the request to.
To fix it, you need to define what controller you want the top mapping to route to. This is how I did this in a recent project of mine:
"/uploaders/$id" {
controller: "uploader"
}
To map to just a view:
"/$customer/index"(view: "/${params.customer}/index")

How to prevent Grails from rendering the default view?

I'm using Grails 1.2.1. I have this method in my controller …
class SocialMediaCacheProxyController {
def index = {
def url = params.url
if (params.dumpAll != null) {
transportCacheService.processCacheDump(request.getRemoteAddr(), response)
} else if (url != null) {
doCacheTransport(request, response)
} // if
}
Problem is, both execution paths write content to the response. However, I think Grails is trying to render a page at the end of the index method, because I repeatedly get the below error after invoking this method …
1339754 [http-8080-4] ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/socialmediaproxy].[default] - Servlet.service() for servlet default threw exception
java.lang.IllegalStateException: response.getWriter() called after response.getOutputStream()
at org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper$GrailsBuffer.getWriter(GrailsPageResponseWrapper.java:284)
at org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper$3.activateDestination(GrailsPageResponseWrapper.java:125)
Any ideas how I can get Grails to stop rendering anything after my method is complete? Thanks, - Dave
If you don't tell Grails what to render, it will render based on convention. In your case, it is looking for an index.gsp. Controllers must return something. That's the whole point. So you can either use the convention and create an index.gsp that gets returned, or you can manually implement the render() method.
http://grails.org/doc/latest/ref/Controllers/render.html
It looks like most of the controller code that works with the ModelAndView keeps an eye on whether or not the ServletResponse has been committed.
I would posit that you could call response.flushBuffer() at the end of your controller action. This will cause the response to be marked as committed, and the controller will not return a ModelAndView.
An alternative would be to call response.outputStream.flush(), which would also result in the response being committed. This is what I usually end up doing after manually working with the response (e.g. for file downloads).
Note: I'm not sure where this falls within the realm of "best practices" - usually you're supposed to rely on the container to handle the flushing of the servlet streams. It's possible that there will be inadvertent side-effects by doing this. You'll probably have to test it out and see what happens with your app and the container you run it in.
I think you're trying to do something counter to the design of an MVC application. Controllers exist to send you somewhere based on parameters. Maybe you could look at using a Service instead, through an AJAX call. Or, if your controller action is changing data that you want to show, you could just redirect back to the page that the call came from. Start here:
http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html
http://grails.org/doc/1.0.x/guide/8.%20The%20Service%20Layer.html
I think Grails maybe forwarding to index.gsp, because it does so by default when you don't return a value.
Therefore, i think you should return null at the end of the index-closure to signal grails that you have already written everything you wanted to the output stream.
try this
render (view: "/the name of the page", model: [text:'hi there')
NB
if u want to render a template instead of "view" you put "template"

URL Mapping prefix in Grails

Recently, I'm trying to migrating my application from CakePHP to Grails. So far it's been a smooth sailing, everything I can do with CakePHP, I can do it with much less code in Grails. However, I have one question :
In CakePHP, there's an URL Prefix feature that enables you to give prefix to a certain action url, for example, if I have these actions in my controller :
PostController
admin_add
admin_edit
admin_delete
I can simply access it from the URL :
mysite/admin/post/add
mysite/admin/post/edit/1
mysite/admin/post/delete/2
instead of:
mysite/post/admin_add
mysite/post/admin_edit/1
mysite/post/admin_delete/2
Is there anyway to do this in Grails, or at least alternative of doing this?
Grails URL Mappings documentation doesn't help you in this particular case (amra, next time try it yourself and post an answer only if it's any help). Daniel's solution was close, but wouldn't work, because:
the action part must be in a closure when created dynamically
all named parameters excluding "controller", "action" and "id" are accessible via the params object
A solution could look like this:
"/admin/$controller/$adminAction?/$param?"{
action = { "admin_${params.adminAction}" }
}
The key is NOT to name the parameter as "action", because it seems to be directly mapped to an action and can not be overriden.
I also tried a dynamic solution with generic prefixes and it seems to work as well:
"/$prefix/$controller/$adminAction?/$param?"{
action = { "${params.prefix}_${params.adminAction}" }
}
I didn't test it, but try this:
"mysite/$prefix/$controller/$method/$id?"{
action = "${prefix}_${method}"
}
It constructs the action name from the prefix and the method.
Just take a look on grails URL Mappings documentation part

Grails UrlMappings with .html

I'm developing a Grails web application (mainly as a learning exercise). I have previously written some standard Grails apps, but in this case I wanted to try creating a controller that would intercept all requests (including static html) of the form:
test 1
test 2
test 3
test 4
The intent is to do some simple business logic (auditing) each time a user clicks a link. I know I could do this using a Filter (or a range of other methods), however I thought this should work too and wanted to do this using a Grails framework.
I set up the Grail UrlMappings.groovy file to map all URLs of that form (/$myPathParam?) to a single controller:
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
}
}
"/$path?" (controller: 'auditRecord', action: 'showPage')
"500"(view:'/error')
}
}
In that controller (in the appropriate "showPage" action) I've been printing out the path information, for example:
def showPage = {
println "params.path = " + params.path
...
render(view: resultingView)
}
The results of the println in the showPage action for each of my four links are
testJsp.jsp
testGsp.gsp
testHtm.htm
testHtml
Why is the last one "testHtml", not "testHtml.html"?
In a previous (Stack Overflow query) Olexandr encountered this issue and was advised to simply concatenate the value of request.format - which, indeed, does return "html". However request.format also returns "html" for all four links.
I'm interested in gaining an understanding of what Grails is doing and why. Is there some way to configure Grails so the params.path variable in the controller shows "testHtml.html" rather than stripping off the "html" extension? It doesn't seem to remove the extension for any other file type (including .htm). Is there a good reason it's doing this? I know that it is a bit unusual to use a controller for static html, but still would like to understand what's going on.
This is related to content negotiation, which you can read about in section 6.8 of the Grails user guide. If Grails recognises the extension as a particular type, the extension is removed from the URL and the type is added to the "format" parameter.
You can disable this behaviour by adding this entry to grails-app/conf/Config.groovy:
grails.mime.file.extensions = false

Resources