Call Grails Controller method without having a view for it - grails

I am using Grails 3, and am working on a template page, which contains the outline for the rest of the website. I and am attempting to call a method from a controller, by using the following code, as recommended by the official documentation:
<g:include controller="layouts" action="loadUsers" />
My controller looks as follows:
class LayoutsController {
def loadUsers() {
println("we are in here")
}
}
When the include statement gets executed on my embedded tomcat, I get the following error:
[http-nio-8443-exec-4] ERROR o.a.c.c.C.[.[.[.[grailsDispatcherServlet] - Servlet.service() for servlet grailsDispatcherServlet threw exception
javax.servlet.ServletException: Could not resolve view with name 'loadUsers' in servlet with name 'grailsDispatcherServlet'
Ofcourse, the error makes sense, as I do not have that view/gsp page. I want to just simply invoke a method to create some stuff in the backend, not tie it to a gsp page. Is this possible? Basically, a similar approach to JSF where I can execute a public method on a bean.

When a controller action is invoked, unless the action invokes something like redirect or render, then a view will be rendered. That is by design and how controller actions are supposed to behave. If the view isn't present, then an error occurs.
It isn't clear what you are trying to do but if you are just trying to invoke some logic and you don't want a view that is a little bit of an unusual thing to be doing from a GSP, but you could do it by invoking a custom GSP tag that does whatever it is you are trying to accomplish. Normally all of that sort of thing is done before the view is rendered (so, before any GSP code is involved).

Related

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.

Can't access domain class methods in loaded template

I'm using Grails 1.3.8 (old but gold). In my view I render a template with the same variables as of the containing view via:
<g:render template="areaInfoTemplate" model="${pageScope.variables}"/>
This works unless I try to access methods on domain classes inside the template:
<g:if test="${currentState == State.findByName('foobar')}">...</g:if>
Leads to:
Exception Message: Cannot invoke method findByName() on null object
If I access State in the main view gsp everything is ok.
My domain class is:
class State {
String name
String value
static constraints = {
name(nullable:false,blank:false,size:0..255)
value(nullable:false,blank:false,size:0..255)
}
}
Grails isn't PHP - please don't make database calls from the view layer (unless you like to fight artificial, self-inflicted scalability issues). Just make the calls in a controller or service and pass the data to the view to be rendered. GSPs should only be responsible for rendering output, not higher-level concerns like database access.
I forgot to add an import statement at the beginning of the file:
<%# page import="my.wonderful.package.State"%>

Grails Custom Scaffolding get access to controller name

I am trying to write a custom src/templates/scaffolding/Controller.groovy and was wondering if there was any way to get access to the controller name? Right now it seems like you can only get the "model" class. The reason I need it is I am customizing the render to prefix the templates directory based on the controller.
For instance I have a controller named AuthorAdminController and I need to customize the list to use the /admin/user/** directory.
Let me know if you have any questions. I am getting ready to look into how to customize DefaultGrailsTemplateGenerator but I am not sure if that is the correct route to go.
Example:
class UserAdminController {
static scaffold = User
}
Currently in my Controller.groovy I get className='user' so I have no access to the controller.
I don't think you can, as the way scaffolding works your template will always be generating a class named DomainClassNameController (i.e. UserController in your example), which gets loaded into a new classloader and then the metaclass of the real controller (UserAdminController) gets new actions added to it which delegate to an instance of the generated UserController.
Now every controller has access to the controllerName property during execution of actions, so this may provide you with a workaround. I haven't tried it, but you could try putting a log.info("controller: \${controllerName}") into the template and see which name it gives you (the backslash to make it resolve at runtime rather than generation time).

struts2 when action returns input included actions in freemarker do not call execute

We have a number of Freemarker pages that have action calls within them, for example:
The problem we are having is that if the action that renders the page returns INPUT for any reason then the execute() method of the included action does not get called. Instead, only the validate method gets called. This means that the logic for the action is not executed. I would have thought that the included actions invocation should be independent of the result of the 'parent' action.
To workaround we are having to add input result mappings to the header action mapping to exactly the same as success mappings, and also explictly call execute within the validate method. This is unclean and seems wrong.
Is this a struts2 bug or is there something I am missing?
Thanks
Matt

How to prevent Grails from rendering the default view?

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"

Resources