Grails render changes url to index - url

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()
}

Related

Grails gsp won't render correctly

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' )

What happens to render view call when filter returns false?

I have a filter that does some check and returns false based on that check failure. But, before it returns false it renders error view that should be displayed to user in case of such errors. Instead, a blank page is displayed with error code 404. Note that url contains controller and action that do not exists so normally a 404 would make sense but since i have applied a global filter here which gets called and makes the render call, i am concerned about that render call which didnt materialized.
Can you share code ?
I guess you try to render something that does not exist.
Following code works for me
def filters = {
before = { Map model ->
...
render (view: '/access-denied')
return false
}
and it renders access-denied.gsp
Also usually I am not rendering view in this kind of case, Instead I am redirecting it something like following
before = { Map model ->
...
redirect(uri: '/access-denied')
return false
}
You can use forward to render a view in a filter. E.g.
all(controller:'*', action:'*') {
before = {
if(requirePost && !"post".equalsIgnoreCase(request.method)) {
response.status = 405
response.setHeader('Access','POST');
forward(controller: 'page', action: 'http405')
return false;
}
}
}
This way the URL does not change.

redirect in grails

I am redirecting an uploaded image in grails like so:
Controller:
def upload() {
def f = request.getFile('myFile')
if (f == null | f.empty) {
flash.default = "file cannot be empty"
errors.getFieldError("cannot be empty")
return
}
def fName = f.getOriginalFilename()
def picture = new Picture(orgName: fName, urlOrg: "http://localhost/"+fName)
f.transferTo(new File('/Users/sagarmichael/Desktop/photoUpload/'+fName))
println("saved")
redirect(action: 'test', params: [url1:picture.urlOrg] )
}
def test(){
System.out.println(params.url1)
[url1:params.url1]
}
I would expect this to then send url1 to my view called test where I have this:
<img src="${url1}"/>
I would expect this to then show the image on screen.
I have the apache2 config set correctly and when i go to
http://localhost/<imageName>
it works correctly.
What I am getting is this in the url bar on the browser:
http://localhost:8080/FYP/profile/test?url1=http%3A%2F%2Flocalhost%2Flonglogo3.png
any ideas?
If you use the redirect method with params they will appear in the url. To omit this, you will need to think in another way to design your code.
Looking at your code, it appears that you do the upload of some image and need to show the result. I suggest you pass just the name of the image to your other method and mount the link dynamic (not always will be localhost, wright?). The output url will be:
http://localhost:8080/FYP/profile/test?image=longlogo3.png
If you need to omit the name of the image too you will have to store this in the session.
You are mixing model and URL params. If you really need to have it like this, you have to put the content of param 'url1' into the model in the test() action:
def test() {
return [ 'url1': params.url1 ]
}
I hope, you get the point, I definitely recommend to redesign the code ;-)
Try
render(view:"test", model: [url1:picture.urlOrg])
Or
chain(action: "test", model: [url1:picture.urlOrg])

Detect redirect in Grails

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
}

Can I have a circular redirect in Grails?

I'm trying to redirect circularly in Grails (no infinite redirect loop) and keep getting this error:
org.codehaus.groovy.grails.web.servlet.mvc.exceptions.CannotRedirectException:
Cannot issue a redirect(..) here. The
response has already been committed
either by another redirect or by
directly writing to the response.
I am trying to do something like this where I redirect to another action on the controller then redirect back. Wondering why Grails is not allowing this.
//initial action and final redirect location
def showStuff = {
if (flash.neatStuff){
return render("found neat stuff")
} else if (params.email) {
return redirect(action:'getNeatStuff',params:[email:params.email, emailOnly:true])
}
return render("Unable to find stuff, use param")
}
def getNeatStuff = {
flash.neatStuff = new Date()
if (params.emailOnly){
redirect(action:'showStuff')
}
redirect(action:'someOtherPlace')
}
Ok, I had a total brain fart. I corrected the code below in case anyone runs into this same error. I was racking my brain looking at other things, but I just wasn't returning the redirect on the action.
def getNeatStuff = {
flash.neatStuff = new Date()
if (params.emailOnly){
return redirect(action:'showStuff')
}
redirect(action:'someOtherPlace')
}

Resources