How can I use path variables in grails controller?
Asked Answered
C

1

5

I have been trying to use a path variable in grails controller but I am not able to achieve it. The intention behind is to validate the parameter submitted to the url which I need to make mandatory. I could not achieve it through RequestParam so I switched to PathVariable so that the url submitted without the required param should be filtered off by grails controller itself rather than me adding if/else checks for validity.

So, I can illustrate as below: My URL is something as below:-

'<appcontext>/<controller>/<action>?<paramName>=<something>'

Now, to make 'paramName' mandatory I am not finding any way in Grails(Spring MVC provides @RequestParam annotation which can enable me for 'required' as true).

Another alternative I thought was to use path variables so that 'paramName' can be included in URL itself. So I tried like following:

'<appcontext>/<controller>/<action>/$paramName'

For validating the above URL I wrote specific mapping but some how it does not work too..

Following is the specific mapping I wrote:-

"/<controllerName>/<action>/$paramName" {
            controller:<controller to take request>
            action:<action to do task>
            constraints {
                paramName(nullable: false,empty:false, blank: false)
            }
        }

I tried to use spring annotation like @PathVariable and @RequestParam in controller as given below:-

 def action(@PathVariable("paramName") String param){
        //code goes here
    }
Camiecamila answered 2/7, 2014 at 11:33 Comment(2)
"some how it does not work too" - what exactly goes wrong? Remember that constraints simply decide whether or not this particular URL mapping could apply to a certain request. If you have other mappings that could match the same URL (e.g. the generic "$controller/$action?/$id?" mapping) then it may be that your constraints are in fact working correctly, rejecting that particular mapping, but the same controller is being called through a different mapping instead.Joniejonina
Constraining the parameter with nullable: false, empty: false, blank: false doesn't really do anything. Since the mapping does not include a ?, the parameter has to be present in order for this mapping to apply. You can eliminate those constraints.Conant
C
14

If you name the method argument the same as the request parameter rename, Grails will take care of it for you...

// In UrlMappings.groovy
"/foo/$someVariable/$someOtherVariable" {
    controller = 'demo'
    action = 'magic'
}

Then in your controller:

// grails-app/controllers/com/demo/DemoController.groovy
class DemoController {
    def magic(String someOtherVariable, String someVariable) {
        // a request to /foo/jeff/brown will result in
        // this action being invoked, someOtherVariable will be
        // "brown" and someVariable will be "jeff"
    }
}

I hope that helps.

EDIT:

Another option...

If for some reason you want different names for the method arguments you can explicitly map a method argument to a request parameter like this...

import grails.web.RequestParameter
class DemoController {
    def magic(@RequestParameter('someVariable') String s1, 
              @RequestParameter('someOtherVariable') String s2) {
        // a request to /foo/jeff/brown will result in
        // this action being invoked, s2 will be
        // "brown" and s1 will be "jeff"
    }
}
Conant answered 2/7, 2014 at 17:49 Comment(2)
it worked, however I feel its kinda hack as I wanted a behavior where if the constraint failed, the request should not go through. But here, it is like if it matches an action in controller which has the same name then the request will go through. How can I mandate the request to not take other action (other than URL mapping) without changing the action name from default?Camiecamila
I don't understand your question. No request will ever make its way to the action in your controller unless it matches some corresponding mapping defined in your UrlMappings. For example, if you eliminate the /$controller/$action?/$id? mapping and you have just the URL mapping I defined above, a request to /foo/jeff/brown will work but /demo/magic/ will not. Neither will /demo/magic?someVariable=jeff&someOtherVariable=brown or /demo/magic/jeff/brown etc. The only requests that "get through" are those that match a URL mapping.Conant

© 2022 - 2024 — McMap. All rights reserved.