How to prevent Grails from rendering the default view? - grails

I'm using Grails 1.2.1. I have this method in my controller …
class SocialMediaCacheProxyController {
def index = {
def url = params.url
if (params.dumpAll != null) {
transportCacheService.processCacheDump(request.getRemoteAddr(), response)
} else if (url != null) {
doCacheTransport(request, response)
} // if
}
Problem is, both execution paths write content to the response. However, I think Grails is trying to render a page at the end of the index method, because I repeatedly get the below error after invoking this method …
1339754 [http-8080-4] ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/socialmediaproxy].[default] - Servlet.service() for servlet default threw exception
java.lang.IllegalStateException: response.getWriter() called after response.getOutputStream()
at org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper$GrailsBuffer.getWriter(GrailsPageResponseWrapper.java:284)
at org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper$3.activateDestination(GrailsPageResponseWrapper.java:125)
Any ideas how I can get Grails to stop rendering anything after my method is complete? Thanks, - Dave

If you don't tell Grails what to render, it will render based on convention. In your case, it is looking for an index.gsp. Controllers must return something. That's the whole point. So you can either use the convention and create an index.gsp that gets returned, or you can manually implement the render() method.
http://grails.org/doc/latest/ref/Controllers/render.html

It looks like most of the controller code that works with the ModelAndView keeps an eye on whether or not the ServletResponse has been committed.
I would posit that you could call response.flushBuffer() at the end of your controller action. This will cause the response to be marked as committed, and the controller will not return a ModelAndView.
An alternative would be to call response.outputStream.flush(), which would also result in the response being committed. This is what I usually end up doing after manually working with the response (e.g. for file downloads).
Note: I'm not sure where this falls within the realm of "best practices" - usually you're supposed to rely on the container to handle the flushing of the servlet streams. It's possible that there will be inadvertent side-effects by doing this. You'll probably have to test it out and see what happens with your app and the container you run it in.

I think you're trying to do something counter to the design of an MVC application. Controllers exist to send you somewhere based on parameters. Maybe you could look at using a Service instead, through an AJAX call. Or, if your controller action is changing data that you want to show, you could just redirect back to the page that the call came from. Start here:
http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html
http://grails.org/doc/1.0.x/guide/8.%20The%20Service%20Layer.html

I think Grails maybe forwarding to index.gsp, because it does so by default when you don't return a value.
Therefore, i think you should return null at the end of the index-closure to signal grails that you have already written everything you wanted to the output stream.

try this
render (view: "/the name of the page", model: [text:'hi there')
NB
if u want to render a template instead of "view" you put "template"

Related

What is the right way to detect if a request is a "forward()" from another controller action?

I have a couple of "before" type filters, which I would like to trigger only when a real, non-forwarded request arrives at my server. And not, when I sometimes am forwarding a request to another controller/action for further processing.
My questions if if there is a simple way to detect this particular kind of requests caused by a "forward()" call?
Alternatively, I am considering to parse the request url and check if controller and action match with the current controller/action, but I am not sure if this will work - and it sure is quite an ugly way to handle this issue...
From within my controller action I have tried to see if there were any useful attributes for this purpose on the request object, but could not find any, except from "javax.servlet.forward.request_uri" and "org.codehaus.groovy.grails.CONTROLLER_NAME_ATTRIBUTE" +"org.codehaus.groovy.grails.ACTION_NAME_ATTRIBUTE".
However, it seems like comparing these values with each other will not work if the request uri originates from a UrlMapping,(in which case it might not match with the controller/action)
You can determine if a request was forwarded by looking up the servlet attribute org.grails.FORWARD_CALLED:
request.getAttribute('org.grails.FORWARD_CALLED')
Minimal example (in Grails 3.3.9, though same attribute in 2.5.x):
def index() {
forward action: 'fwd'
}
def fwd() {
if (request.getAttribute('org.grails.FORWARD_CALLED')) {
render 'was called by forward'
} else {
render 'called directly'
}
}
Calling the endpoints:
$ curl localhost:8080/foo/index
was called by forward
$ curl localhost:8080/foo/fwd
called directly

MVC Child action [duplicate]

I have some partial actions that I render with the Asp.Net Futures RenderAction method. Some of these perform redirects after the forms in them have been processed.
Now that I upgraded to Asp.Net MVC 2 RC it gives me an error "Child actions are not allowed to perform redirect actions".
I checked out the source code and I found the line that throws the exception. To Get around it I can make a custom RedirectResult, But before I do I want to understand why the framework doesn't allow it in the first place. There must be a good reason and maybe I Shouldn't do either.
Any one know the reason for this limitation?
Thanks
The limitation exists because MVC has already started rendering a view to the client. The effect of redirecting from this point is undefined. It could work perfectly, it could continue rendering the original view without redirecting, it could throw a different exception, etc.
Since the result of performing this action is undefined, the framework blocks it. In practice, RenderAction should never be used to render anything other than a view (or view-like content) for similar reasons.
In your particular case, the outer action should redirect. If you're just going to end up redirecting from within the view anyway without showing anything to the user, then there was really no purpose to going through the view in the first place, as the outer action could have delegated the work appropriately on its own.
Try to use something like this in Child Action:
ControllerContext.HttpContext.Response.Redirect(ControllerContext.HttpContext.Request.Url.ToString());
My solution.
Action method:
return View("Redirect", model);
View:
<script type="text/javascript" language="javascript">
document.location = '<%: Url.Action("Index", "Album", new { id = Model.Id }) %>';</script>
In my case, the form being rendered is a "configure" panel on an extension to a website I'm building. I'd like the extension's own controller to be able to handle the form processing and then redirect back to the admin page listing all configured extensions. I don't think it's appropriate or practical here to ask the parent page's controller to process the form for the extension. What would you suggest I do instead?
In my unusual case, I had a custom AuthorizeAttribute attached to my controllers which was attempting to redirect on a child action, which is (as mentioned above) not allowed.
To resolve the issue, I removed authorisation checking redirection on all child actions:
Public Overrides Sub OnAuthorization(filterContext As AuthorizationContext)
//Child actions cannot redirect anyway, so no need to check permissions.
If filterContext.IsChildAction Then Exit Sub
.. parent authorisation checks ..
Sometimes this error occured when you try to render an action of base action result.
Example:
ActionResult X
Return View
View X
RenderAction Y
ActionResult Y
// Bla bla
return View
// else
return RedirectToAction X
In that case just point the partial view form's submit url to action that was the target of your problematic redirection and let it perform itself redirection to its GET version.

How to I render validation results in a Grails Web Flow?

I have a Grails WebFlow that is similar to the following example:
def myFlow = {
init {
action {
def domain = MyDomain.get(params.id)
flow.domain = domain ? domain : new MyDomain()
}
on('success').to 'first'
}
first {
on('continue') {
flow.domain.properties = params
if(!flow.domain.validate()) {
return error()
}
}.to 'second'
}
...
}
Given this example, if a validation error occurs in the transition on('continue') in first:
What's the preferred way to set the model with the invalid domain object so I can use a <g:hasErrors>... in my view (like I would in a normal controller action)?
When I call error(), does it send the flow back to init or to first?
Does error() take any arguments (i.e. a model) that can be used for what I'm trying to accomplish (I can't find much documentation on the error() method).
I'd also take suggestions on how I could improve my flow states to better-facilitate handling these validation errors.
Summary: What's the preferred way to render validation errors within a Grails Web Flow?
-1
What's the preferred way to set the
model with the invalid domain object
so I can use a ... in my
view (like I would in a normal
controller action)?
You just need to return your domain object that has the errors. you can do that in an
action state
action {
user.validate()
return [user:user]
}
You can also set your errors in flash scope. On each transition Grails will copy the content of the flash scope into the ModelView and thus available in your gsp page
action {
flash.error = "your message"
}
-2
When I call error(), does it send the flow back to init or to
first? When you call error it call the
transition you defined for
You should define a handler for such as
on("error").to("handlerError")
Does error() take any arguments (i.e. a model) that can be used for
what I'm trying to accomplish (I can't
find much documentation on the error()
method).
I don't think so but you can do the following to set any variable when transitioning from one state to another
on("error") {
// do Something
}.to("handlerError")
3-
I'd also take suggestions on how I could improve my flow states to
better-facilitate handling these
validation errors.
I use flash for global and form errors but i needed ONE way to deal it. Currently with Grails the flash scope is managed differently in a flow than it's managed in a normal action. So I decided to write a little plugin to change the way the flash scope is handled in a flow and make it consistent with the way is managed in a normal action.
I a gsp page i can use my tags in the follwing way regardless of the action type (normal or flow)
<message:global />
or
<message:inline />
As for Form fields errors, i didn't like to deal with errors in domain objects. I wanted something more unified. So I decided to make them part of the http protocol and I have a javascript component the inject them into the form if i opt to. I found this solution much cleaner than dealing with g:errors each time.
-ken
I've found that one way to do it is to specifically invoke render() in the transition state, providing the model. Here's an example where only one field is validated:
first {
render(view: 'info', model: [flow.domain])
on('continue') {
if(!flow.domain.validate(['myField'])) {
return error()
}
}.to 'second'
}
One can then use <g:hasErrors> as follows:
<g:hasErrors bean="${domain}" field="myField">
<g:renderErrors bean="${domain}" as="list" field="myField"/>
</g:hasErrors>

Checking for nulls in ASP.NET MVC Controllers

Another opinion question:
What is the proper (in your opinion) to check for nulls in an MVC controller. For instance, if you have an edit controller that fetches a record from the db based on an id, what do you do if that record is not found? I found this article, but I'm not sure I like that method. Do you just check for it with an if statement and redirect to a 404 page? What solution do you use?
I don't know if it's best practice, but I check with an if and redirect to a "NotFound" view that states "The company/client/whatever you requested does not exist or was deleted."
Did it this way simply b/c I followed the NerdDinner tutorial when setting up the skeleton of my site, and that's how they do it.
That's what I do in my blog:
public ActionResult DisplayPublication (int nr)
{
if (!PublicationExists (nr))
throw new (HttpException (404, ""));
// ....
return ...;
}
As a general rule of a thumb, if a resource is requested which does not in fact exist, return HTTP 404. Definitely not return 200 OK along with the message about the missing resource. If not found, should be 404. If you changed the structure of your urls, consider 301 Moved Permanently.
Depending on the type and logic of the software you're developing, you may decide to exercise a different reaction to that situation, it's up to you.
I use a method similar to the article you linked to: an action filter that returns a 404 if the view model is null. I've combined it with a custom action invoker (like this) so that I don't have to put the filter attribute on everything.
Since I mentioned it, there are several other types of actions you can do if you go the action filter route. I have/had filters that will:
Automatically redirect to the Index view after a successful edit.
Redirect to the same page if the ModelState is invalid.
Redirect to an access denied page if a security exception is thrown.
I'm thinking about refactoring these to a convention registry so I can have something like:
When.ModelIsNull.RedirectTo<SharedController>(c => c.NotFound());
For("Edit").ModelStateIsInvalid.Redisplay();
For("Edit").OnSuccess.RedirectTo("Index");
On<SecurityException>().RedirectTo<SharedController>(c => c.AccessDenied());
Then if I wanted to change how a particular behavior works I just change it in one place. For example, instead of going to Index, I could redirect to the View view.
For("Edit").OnSuccess.RedirectTo("View");
I hope this gives you some ideas.
Edit: Here is how to could accomplish something similar using FubuMVC (which I love to steal ideas from)

How to simiulate a JSON call from an HTTP GET Call?

At this moment I am calling my index view in one of two ways. Using the normal http view and serializing it JSON. In order to test it I am using the code below, and it works. I want to get it with a http get call. Like (http://localhost/article,json or something similar. Any ideas.
$.getJSON("/Article", function(json) {
$.each(json, function(i, article) {
alert(article.title);
});
});
At this moment the index called to /article is being differentiated with the following IsAjaxRequest method. but my real question is if I am able to get around the .getJSON method in JQuery to test the following code.
if (Request.IsAjaxRequest()) {
return Json(articles);
} else {
return View(articles);
}
If you are trying to reuse the same action method for both a full GET (the page load) and an AJAX call (via getJSON), you'll run into issues because each action method should have a unique name. Otherwise, the MVC engine can't tell which action method should be called when a particular Url is requested.
You'll need two separate actions: one for the full page load that returns a ViewResult and the other for the AJAX call that returns a JsonResult. If you need the Urls for these actions to look the same, you can also play around with mapped routes that direct to different action methods.
So, how about:
/Article/Index
Maps to the default Index action (full page load)
/Article/Refresh
Maps to the Refresh action (asynchronous JSON call)
I'm not sure I understand the question correctly, but can't you make an optional parameter called "format", so that you pass in ?format=json to switch what reply type you get back?
if(Request.IsAjaxRequest() || (!string.IsNullOrEmpty(format) && format.Equals("json"))
{
...
}
If you're wondering how to test your action and you're talking about doing automated testing, see if this post answers your question.

Resources