Music, software, life… and stuff.
[ Twitter ] [ GitHub ] [ Linked In ]
Sometimes in a Grails app, you need to call a tag where you can’t call a tag. This is usually indicative of a bad design in your application so do use the following with caution, but should you absolutely need to… the following is how you can.
In this example, we are going to add the ability to call tags to a filter to workaround GRAILS-6814. We want to call the createLink tag.
Note that GRAILS-6814 has been resolved for Grails 1.4, so this workaround for redirects to a different domain only applies to Grails 1.3 and earlier
import org.codehaus.groovy.grails.web.pages.GroovyPage
import org.springframework.web.context.request.RequestContextHolder
class HttpsOnlyFilter {
def gspTagLibraryLookup // need this autowired
def filters = {
redirectToHttps(controller: "*", action: "*") {
before = {
if (!request.secure && isSecurePage(controllerName, actionName)) {
def link = invokeTag("createLink", [
controller: controllerName,
action: actionName,
params: params,
base: "https://secure.domain.com"
]).toString()
response.status = 301
response.setHeader("Location", link)
false
}
}
}
}
def invokeTag(name, attrs = [:], body = null) {
def namespace
def tagName
if (name.contains(":")) {
def split = name.split(":", 2)
namespace = split[0]
tagName = split[1]
} else {
namespace = GroovyPage.DEFAULT_NAMESPACE
tagName = name
}
GroovyPage.captureTagOutput(gspTagLibraryLookup, namespace, tagName, attrs, body, RequestContextHolder.currentRequestAttributes())
}
}
The invokeTag method takes; the name of a tag, a map of attributes, and an option body closure and returns a StreamCharBuffer (so if you want the content as a String you new to toString() the return). Inside the body closure, you can write to the out stream just like in a tag implementation.
If the tag name given to invokeTag() doesn’t include a namespace, the default g namespace is used. To invoke a tag in a different namespace, you can use…
invokeTag("someNamespace:someTag", [param1: 1])
Remember, requiring tags outside of the view layer can be indicative of a design problem so do think long and hard about whether you really need to before using the above. Also, the above will only work in a request environment so if you try to use the above on a background thread were a fake request environment hasn’t been established it will blow up due to RequestContextHolder.currentRequestAttributes() returning null. If you need to setup a fake request environment, you can use GrailsWebUtil.bindMockWebRequest() to do so.
Posted: May 11th, 2011 @ 11:40 am