Grails UrlMappings (Ryan Headley)

, June 23rd, 2008

Original Source

Ryan Headley writes about his recent experience with Grails UrlMappings. Grails follows the Convention over Configuration paradigm (as you probably know by now), but that doesn’t mean it will throw away configuration out of the window. Ryan describes a scenario where he would like to reuse an existing controller for two different URLs. If Grails were to follow the CoC paradigm blindly he would surely have had to copy the first controller in order to get the url mappings right.

I [Ryan] am using Grails on one of my current projects in which end-users can enroll in a couple of “different” programs offered by my client.  Behind the scenes, these programs are identical except for the name.  However, the look and feel of the enrollment process will have subtle difference based upon the program that the end-user is enrolling in.

Since the code and the majority of the views are exactly the same, I want to use one controller and just hold the program name in session and refer to it when I need to specify something about that particular program.  Sounds easy enough right?  Well, it is easy UNLESS you want to maintain completely separate URLs for the process.  My client is very interested in tracking this sort of information in Google Analytics and for some reason the urchin tracker isn’t producing the desired results.

Originally, I was giving two possible entry points into this enrollment process, one for each program, but once inside, everything was referring to the same controller.  So how then do I maintain two separate url schemas and still use the same backend controller?  The answer:  UrlMappings.groovy

So how did he do it? After searching around for info and some trial and error he ended with something like this

class UrlMappings {
static mappings = {
“/product2/$action?/$id?” {
controller = “product1″
constraints {
action(matches:”apply|qualify|thankyou”)
}
}
}
}

Which means that any action that matches “apply”, ‘qualify” or “thankyou” called on an url that contains “/product2″ will be actually handled by the controller mapped by “/product1″. In his own words:

This mapping takes all requests for product2 controller and refers it behind the scenes to the product1 controller/action.  The kicker here is the “action(matches:…)” line.  If we request /product1/somethingelse, this mapping won’t match.  (There are certain situations in my project that we had to have some other actions on product2’s controller that product1 didn’t have.  In this case, I created the product2 controller and just added that action.)  If the action “matches” the mapping takes over and uses product1/action behind the scenes while the URL still reads /product2.  Nifty!!  (NOTE:  Take note of the trailing “?” in the mapping url.  It signifies it as an optional parameter.  If I were to put a question mark after the action, everything under product2 would map to product1 which may not be desirable, and for me, it wasn’t).

A Gotcha – One thing I ran into however, was that once I added this mapping, I noticed that the links in my product1 views started pointing to product2’s controller which wasn’t making sense.  So I added another mapping pointing /product1 to its own controller which remedied the problem.  I’m sure if I think about it long and hard enough, I’ll figure out why that was needed, but perhaps that’s for another entry.

In closing, I’m finding that the more I ask of Grails, the more pleased I am with the answers it provides.  It took me a while to get the mappings to work quite right, but once I did it worked like a charm.  Perhaps there are better ways to skin this cat, but this solution worked for me and took very little “coding/configuration” to get the desired result.

You may find more info on URLMappings at the Grails Documentation Site.

Tags: ,