How to nest Grails controller paths

1.7k views Asked by At

I know it is possible to do something like this:

Controller foo with action bar can be accessed by (1):

/appname/foo/bar

And it can be rewritten using URL mappings - e.g like this:

"/foobar/foo/$action"(controller: "foo")

And then access it via (2):

/appname/foobar/foo/bar

But it is still possible to access it via (1). This is of course because of the default URL mapping:

"/$controller/$action?/$id?"()

But I would rather not delete this, because this basically means I have to manually write mappings to every other controller/action that follows the default pattern.

It is possible to obtain url-patterns for specific controller/actions like (2) without using URL mappings? If not, is there an easy way to "exclude" controllers from the default mapping closure?

2

There are 2 answers

3
derdc On

If you can make your rule breaking scenario more specific than the Grails default $controller/$action?$id? pattern, then the default can be left as is and will apply to everything outside of your exception pattern. I made a quick Person domain and performed a generate-all. Then I made a BreakRuleController just by itself.

class UrlMappings {

static mappings = {

    "/b/$action?/$someVariable?"(controller: "breakRule")

    "/$controller/$action?/$id?(.${format})?"{
        constraints {
            // apply constraints here
        }
    }

    "/"(view:"/index")
    "500"(view:'/error')  
   }

}

With this UrlMapping, if you access the URI "/b/foo/stackoverflow" it will print "Breaking Rules foo: stackoverflow". If you go to "/b", it will print "Breaking Rules index".

Then if you go to the standard Person URI's, all your default Grails scaffolding works fine also (create, edit, etc.) because that gets mapped to the typical "$controller/$action?/$id?" pattern.

class BreakRuleController {

   def index() {
       print "Breaking Rules index"
   }

   def foo(String someVariable) {
       print "Breaking Rules foo: " + someVariable
   } 

}

0
Falk Nisius On

The Solution is to change the default mapping, in a way to exclude the whished special controller URL.

class UrlMappings {

  static myExcludes = ["foo"]

  static mappings = {
    "/foobar/foo/$action"(controller: "foo") // your special Mapping

    // the rewritten default mapping rule
    "/$aController/$aAction?/$id?"{ 
        controller = { (params.aController in UrlMappings.myExcludes) ? "error" : params.aController }
        action = { (params.aController in UrlMappings.myExcludes) ? "notFound" : params.aAction }
        constraints {
            // apply constraints here
        } 
     }
  }
}

For the rewritten default rule you have to prevent usage of default variable names $controller and $action. Instead of error/notFound you are also able to redirect to other locations.