I am new to grails and I am trying to override the redirect method in groovy controller. I refereed this Override Grails redirect method. But I do not understand how do I access and pass the http request params to the redirect override in BootStrap.groovy.
redirect(action: "logout", params: [lang: params.lang])
If you implement a wrapper via metaClass on a controller (just like mentioned in your linked question), you can simply access the "active" controller object via "delegate" in your implementation closure:
def ctx = servletContext.getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
def app = ctx.getBean("grailsApplication")
app.controllerClasses.each() { controllerClass ->
def oldRedirect = controllerClass.metaClass.pickMethod("redirect", [Map] as Class[])
controllerClass.metaClass.redirect = { Map args ->
// delegate is the instance of <controllerClass> where "redirect" just gets executed.
// the current http request can be accessed via a getter on controller classes
println delegate.getRequest()
oldRedirect.invoke delegate, args
}
}
alternatively, you could use the RequestContextHolder to obtain the current requestAttributes and extract the request from there (see org.codehaus.groovy.grails.plugins.web.api.CommonWebApi.java in Grails 2 or grails.web.api.ServletAttributes.groovy in Grails 3)
Related
I have successfully set up my Grails application to authenticate the user.
I map controller method arguments using URL params, in my UrlMappings.groovy:
"/$source/owner/$ownerId/show"(controller:"myController", action: "show", method: "GET")
How do I get the values of $source and $ownerId in my #Secured closure?
My controller method looks like this:
#Secured(closure = {
//null
def testSource = params.source
//also null
def testOwnerId = params.ownerId
//null
def owner = request.ownerId
//null
def owner2 = request.getParameter('ownerId')
//contains only query string params
def grailsParams = request['org.codehaus.groovy.grails.WEB_REQUEST']?.params
return true
})
def show(String source, String ownerId) {
...
}
How do I get these values? What am I doing wrong, here?
I thought that this post would provide a solution, but the answer given there didn't work for me:
Is it possible to hack the spring-security-core plugin #Secured annotation to be able to reference request params given to a controller?
I am using the following grails and plugin versions:
grails 2.5.1
compile ":spring-security-core:2.0-RC5"
compile ":spring-security-rest:1.5.3", {
excludes 'com.fasterxml.jackson.core:jackson-databind:'
}
Brief :
Use request.getParameter
Details :
In 2.0 you can use a closure as the annotation's check; there's a brief writeup and example in the docs: https://grails-plugins.github.io/grails-spring-security-core/v2/guide/newInV2.html
You'd express your example as this:
#Secured(closure={
request.getParameter('ownerId') >=123 //this is example
})
Return true to allow access, false to deny access.
At the end of my save action I redirect to the show action like this:
redirect(action: "show", id: exampleInstance.id)
In my show action I want to be able to detect if someone came directly to this action via a url, or if they were redirected here from another action. I tried request.isRedirected() but it always returns false.
How do I detect if I am in an action as the result of a redirect from another action?
I guess you want to display a confirmation message. Grails has a built-in feature for this kind of use-case:
http://www.grails.org/doc/2.1.0/ref/Controllers/flash.html
Have a look at the example:
class BookController {
def save() {
flash.message = "Welcome!"
redirect(action: 'home')
}
}
In the view you can print or check against flash.message.
In theory, isRedirect checks request attributes. It is equivalent to
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
if(request.getAttribute(GrailsApplicationAttributes.REDIRECT_ISSUED) != null){
println "request was redirect"
}
Try it directly and tell me what happens.
It looks like in the Grails source that isRedirected() is only applicable to the save action, as it gets set in the redirect() method logic, and so wouldn't be set in the show action.
Instead, here are some manual options. One is to add a flag to the flash object, which is then tested in the redirect action. Since it is in flash scope it will be cleared at the end of the show action:
def save() {
// Do stuff
flash.redirectFrom = "save"
redirect(action:"show")
}
def show() {
if (flash.redirectFrom) {
// Respond to redirect
}
// Do other stuff
}
Another option is to issue a chain() call instead of a redirect() and test for the implicit chainModel object. The chainModel won't exist when the show action is requested from an external URL:
def save() {
// Do stuff
chain(action:"show",model:[from:'show'])
}
def show() {
if (chainModel) {
// Respond to redirect
}
// Do other stuff
}
I have one gsp file which calls a method like this:
<g:link id="${child.id}" action="callChildProfile" controller="profile">${child.firstname}</g:link>
which calls this method
def callChildProfile(Long id){
childInstance = Child.get(id)
System.out.println(childInstance.firstname + " child instance")
redirect(action: "index")
}
this method set a child instance to a public variable called child instance but when the redirect happens the variable is reset.
The reason I redirect is because I want to load up the index page from this controller.
Index looks like this:
def index() {
def messages = currentUserTimeline()
[profileMessages: messages]
System.out.println(childInstance + " child here")
[childInstance : childInstance]
}
By default controllers are prototype scoped, which means the instance of ProfileController used will be different between the request which calls callChildProfile and the request which calls index. Thus, the object level childInstance variable won't be available between requests.
To use the Child instance in the index call, look at the chain method:
callChildProfile(Long id){
// do usual stuff
chain(action:"index", model:[childInstance:childInstance])
}
def index() {
// do other stuff
[otherModelVar:"Some string"]
}
When returning a Map from index the model of the chain call will be automatically added, so your childInstance from the callChildProfile will be available for the gsp.
Variables in controller methods (actions) have a local scope, thus, only can be used in that method. You should pass the id from new instance and use that id for retrieve the object.
redirect action: "index", id: childInstance.id
and index could be
def index(Long id){
childInstance = Child.get(id)
Then you can conclude that you don't need the callChildProfile method
or you can use params
def index(){
childInstance = Child.get(params.id)
if(childInstance){
doSomething()
}
else{
createOrGetOrDoSomethingElse()
}
}
In my controller, I want to accept only POST variables, not the GET Variables. Grails doesn't make any distinction between POST and GET, as far as I know, though the request method can be checked via request.method, but I want to specifically only accept POST parameters. How to go about it? Sorry, if I sound too naive, I have just started groovy and grails with my background in PHP.
Isn't this what the allowedMethods block is for
ie from the documentation:
class PersonController {
// action1 may be invoked via a POST
// action2 has no restrictions
// action3 may be invoked via a POST or DELETE
static allowedMethods = [action1:'POST',
action3:['POST', 'DELETE']]
def action1 = { … }
def action2 = { … }
def action3 = { … }
}
Is it possible to access the current controller instance from within a TagLib? For example:
class FooTagLib {
static namespace = 'foo'
def msg = { attrs, body ->
// Can I get a reference to the current controller here?
}
}
I want to do this because I store some data in a property of the controller and want to access it within the TagLib. I realise this may sound strange, but just humour me....
Inside your msg tagLib:
grailsApplication.getArtefactByLogicalPropertyName('Controller', pageScope.controllerName)
Like Views, you have access to the current controller and action through controllerName and actionName
Try something like this...
def ctl = grailsApplication.getArtefactByLogicalPropertyName('Controller', 'whateverController')