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
}
Related
Note: Second action only allows POST method. we can not hit that action by the user.
static allowedMethods = [save: "POST",booked:"POST"]
def save()
{
// did save operation here
redirect action:'booked'
}
def booked()
{
//did the operation related with this
render view :'payment'
}
Try forward
def save()
{// did save operation here
forward action:'booked'
}
def booked()
{
//did the operation related with this
render view :'payment'
}
All the parameters passed to save will directly get passed to booked method. Is this what you need?
You may do this as below by directly calling the method within save method
def save(){
booked()
}
This is the main login page of my application:
Once you're logged in, you see this page:
Now on this page if you press the 'Choose/Upload' button (circled in blue), you get a template rendered in the middle part of the page and then it looks like this:
If you wait a while such that your session becomes null, then I want the 'Choose/Upload' button to redirect back to the login page, which it does but things look like this:
This is the controller function associated with the 'Choose/Upload' button:
def chooseupload = {
if (session.user == null) {
redirect(action: customerLogin)
}
else {
def batchList = (Batch.findAllWhere(userId: session.user.id.toLong(), [sort: "lastUpdate", order: "desc"]))
render(template: 'chooseupload', model: [batchList: batchList, batchCount: batchList.size()])
}
}
and this is the code of the login action:
def customerLogin = {
} //just renders the view customerLogin.gsp
Any advice greatly appreciated. I am happy to provide more relevant code if needed.
you seem to be calling chooseupload in an AJAX request. If you call redirect in the controller, the browser gets the fully decorated (with header & footer) page back. In order to be able to differentiate between AJAX/noAJAX calls, I'm using the following code:
request.xhr ? render( template:'customerLogin' ) : redirect( action:'customerLogin' )
I've got this method on my controller, which basically validates and saves entity or renders errors if any:
def initCreateProduct() {
render view: "/admin/product/createProduct"
}
def createProduct(params) {
def product = new Product(params)
if (product.validate()) {
flash.message = "product.createSuccess"
product.save(failOnError: true);
redirect action: "initCreateProduct"
} else {
render view: "/admin/product/createProduct", model: [product: product]
}
}
It works fine in case if validation is successfull (URL in browser is "product/initCreateProduct", which is ok), but in case if validation fails my URL changes to "product/index", which is wrong. What I need is to get the same URL in both cases (it's the same page after all). Thanks in advance.
Update: finally solved it.
The problem is caused by used in my gsp, which basically changes action url to index, and sends real action as post-method parameter. To save action in url I have used instead of
It is doing a controller redirect and not being able to resolve an URL. IIRC, grails will pass additional parameters to the index method to find that action.
If you do something like this, it won't do it:
if (product.validate()) {
flash.message = "product.createSuccess"
product.save(failOnError: true)
initCreateProduct()
}
i have a controller that is not on webflow but need to redirect it to a weblflow. The problem is the view I need to access is inside an action of a webflow.
here is my webflow
class EditSpouseContactInfoController {
def index = { redirect(action:"editSpouseContact") }
def editSpouseContactFlow = {
start{
action {
//some codes here
}
on("success").to("editSpouseContact")
on(Exception).to("editSpouseContact")
}
editSpouseContact {
/************************************/
// Veteran Marital History Processing
/************************************/
on("addMaritalHistory"){
flow.contactInstance.properties = params
if(!flow.maritalHistoryLst){
flow.maritalHistoryLst = []
}
conversation.maritalHistoryInstance = new MaritalHistory()
conversation.maritalHistoryInstance.isVeteranMaritalHistory = false
}.to("editSpouseMaritalHistory")
}
}
here is my non weblow controller:
def addMaritalHistory={
MySession session = MySession.getMySession(request, params.id)
def caseInstance = CmCase.get(params.cmCaseIdCmCase.id as Long)
redirect(controller: "editSpouseContactInfo", action: "editSpouseContact ", id:caseInstance.id)
}
The line above works but is it possible for me to directly access addMaritalHistory inside editSpouseContact?like instead of using the above action it would be action: "addMaritalHistory"? Of course it is not working but is there a way to call that as action? thanks
The whole point of web flow is that you can't jump directly into the middle of a flow from outside it. You'll have to add some logic to the initial start state to check for certain parameters in the incoming params and jump to the appropriate state from there.
def handleLogin = {
def hashPassd = DU.md5Hex(params.password)
// Find the username
def user = User.findByUserNameAndPassword(params.userName, hashPassd)
if (!user) {
flash.message = "User not found for userName: ${params.userName}"
redirect(action:'index')
return
} else {
session.user = user
redirect(controller:'todo')
}
}
how come the if condition requires the return statement? and the else block don't require it?
In this case the return is not necessary. If the return isn't there it will continue to after the if, which is the end of the method, and thus returns.
The return is not strictly necessary but it's a good habit to get into. Calls like render and redirect in a controller action are usually intended to be the conceptual "end" of the action, and its easy to forget sometimes and treat the redirect as if it were a return
def someAction() {
if(!params.id) {
flash.message = "no ID provided"
redirect action:'error'
}
def myObj = MyObj.get(params.id)
//...
}
This will fail at runtime, probably with a rather obscure error message, and to avoid this possibility it's a good idea to remember to put an explicit return after any calls to redirect or render. It's the kind of thing that has bitten me when coming back to make changes to a controller action I originally wrote 6 months previously...