meta method inject on Grails Controller - grails

I wrote a plugin to inject a method into all controllers, I wrote this on doWithDynamicMethod {ctx -> }
for (classes in org.codehaus.groovy.grails.commons.ApplicationHolder.application.controllerClasses){
def controllerClass = classes.clazz
controllerClass.metaClass.static.doTestSearch << {args ->
println "this is dynamic insertion -->"+args.toString()
}
classes.class.metaClass.doTestSearch << {args ->
println "this is dynamic insertion -->"+args.toString()
}
}
When i tried to call this method in form in view, by :
<g:form method="POST">
<g:actionSubmit class="save" action="doTestSearch"
value="${message(code: 'default.button.search.label', default: 'Search')}" />
The method doesn't called and returning a 404 error.
But when i tried to call it from controller by :
doTestSearch(params)
It works.
Can someone please explain why is this happening ? And can i call the dynamic method directly from view ?
Thank you in advance

Try this
application.controllerClasses.each {controller ->
controller.metaClass.doTestSearch = {
//Your action code here
}
}
BTW - you can use DynamicController plugin also for adding actions to controllers

It looks like grails can't map the URL for the methods added at runtime but I haven't tested it.

Related

How can i respond to the same gsp view from the controller?

I am pretty new to grails and wondering how to use the respond object to the same view.
Note: I might not be clear with my question - but please check the below stuffs.
I have a one controller called "ProcessController.groovy" which have 2 methods inside them.
I have only one gsp called "create.gsp"
class PublishedSetController {
...
def create() {
Person p = new Person()
...
respond p // Working fine and this forward's to the view "create.gsp"
}
def createClone() {
Person p = new Person()
p.name = 'joe'
...
// Would like to forward to view "create.gsp"
respond view: 'create', model: p
}
}
Error:
Could not resolve view with name 'createClone' in servlet with name 'grailsDispatcherServlet'
I am aware that grails is mostly codeByConvention - but not sure how to fix this issue.
So can anyone please help, Thanks.
Correct syntax for respond is:
respond p, view: 'create'
You can read more about respond in the documentation.

Grails Exception handling getting payload

I have written an grails application, In UrlMappings.groovy file I have url mapping as
"500"(controller:"exception" , action:"internalServerError")
, so whenever any exception occurred I getting the exception in the ExceptionController but I need the payload and the url which throwed this exception , Is it possible to get that data.
Hope this helps. This code is straight from default Grails installation
<g:if test="${Throwable.isInstance(exception)}">
<g:renderException exception="${exception}" />
</g:if>
<g:elseif test="${request.getAttribute('javax.servlet.error.exception')}">
<g:renderException exception="${request.getAttribute('javax.servlet.error.exception')}" />
</g:elseif>
<g:else>
<ul class="errors">
<li>An error has occurred</li>
<li>Exception: ${exception}</li>
<li>Message: ${message}</li>
<li>Path: ${path}</li>
</ul>
</g:else>
in your exceptionController (when a 500 happened) you should be able to access the original URL via
request['javax.servlet.error.request_uri']
additionally you can get the requested URL in every controller via
request[RequestDispatcher.FORWARD_REQUEST_URI]
for accessing the request body after it has been consumed, you could use a solution as suggested in
Accessing the raw body of a PUT or POST request but bear in mind that this of course has to keep the body in memory.
to get the originally called controller and action name inside your exceptionController, the only solution I know right now would be either:
class ExceptionController {
def grailsUrlMappingsHolder
internalServerError() {
// request['javax.servlet.error.request_uri'] sometimes returns null?
def url = request['javax.servlet.error.request_uri'] ?: request[RequestDispatcher.FORWARD_REQUEST_URI]
def originalCall = url ? grailsUrlMappingsHolder.match(request['javax.servlet.error.request_uri'])?.paramss : [:]
def controller = original?.controller
def action = original?.action
...
}
}
alternatively, by saving the first controller call in a filter like that:
class SaveFirstCallFilter {
def filters = {
all(controller:'*', action:'*') {
before = {
// don't want to overwrite when forwarding or including other actions
if (!request['SAVED_CONTROLLER']) {
request['SAVED_CONTROLLER'] = controllerName
request['SAVED_CONTROLLER'] = actionName
}
}
}
}
}

Grails custom tag doesn't work with <g:link params>

I have in my GSP page a <g:link action="test" params='["present": "yes"]' tag which, when clicked, sends me to a URL ending with /test?present=yes.
If I define this custom tag lib:
class HelperTagLib {
static defaultEncodeAs = 'html'
static returnObjectForTags = ['passthrough']
def passthrough = { Map attrs, Object body ->
return attrs
}
}
and add it to the tag, <g:link action="test" params='${passthrough(["present": "yes"])}', suddenly my URL ends with /test, completely losing the params.
Why does this happen and how can I work around it?
Allow your taglib to render that link for you. Try this </g:passthrough> in gsp and in taglib
def passthrough = { attrs, body -> out << g.link(controller: 'foo', action: 'test', params: [present: 'yes']) }
i can see you miss g.taglibname in your call to taglib, it should be like this
<g:link action="index" params="${g.doSomething(present:true)}">Ir</g:link>
i did it my self and its work fine
but if what you want is to intercept some params, and then procesit before complete the request maybe a better solution is using beforeInpreceptor feature or some filter.
more info about interceptors here http://www.grails.org/doc/2.3.x/ref/Controllers/beforeInterceptor.html
hope it can help

MVC3 - Model set to null but still entering IF statement

I have a Model (BusinessPlaceDetailsViewModel) which has another Model (Hub) inside it.
However if I set my Hub to null it still enters my IF condition, see here:
I have tried loads of different combinations like putting each IF statement inside its own braces.
Why is it entering the If block?
I'm betting that it is a problem with the controller not passing the model down to the view.
If you post the controller code it might be helpful.
Just out of curiosity, can you try this and see if the h1 displays?
#if (!User.Identity.IsAuthenticated)
{
if (Model.Hub == null)
{
<h1>wtf shouldn't have gotten here</h1>
}
else
{
...
}
}
Could you handle your check in the controller first? If not maybe try .Any() with Ling.
#using System.Linq
#if( !Model.Any() )
{
...
}
else
I solved this problem by using the following in the BusinessPlaceDetailsViewModel
public BusinessPlaceDetailsViewModel()
{
Hub = new HubViewModel();
}

Grails Web Flow - passing map to first step/state

I'm learning Grails so forgive me if I'm missing something basic.
I'm trying to create a wizard/web flow using the Grails Web Flow plugin. I'd like for the first step of the flow to render some variables. From what I've read about normal controllers, typically this would be done by passing those variables from the controller to the view using a map. In the WebFlow model though, I don't know where to initialize these variables and how to pass them to the first step. I tried creating an initialize "action" and putting the variable into the flash scope, knowing that it should pass through one redirect, but it doesn't render on the gsp.
How is this done?
Here's a snip of the controller, which prints "4" in the console:
class ServicesController {
def index() {
redirect(action: "initialize")
}
def initialize() {
flash.assessmentTypes = AssessmentType.list()
println flash.assessmentTypes.size
redirect(action: "request")
}
def requestFlow = {
selectAssessments {
on("next") {
// capture assessments
}.to("productInfo")
on("cancel").to("finish")
}
...
And a snip of the gsp, which throws a nullpointer when rendering the size:
${flash.assessmentTypes.size}
<g:each var="assessmentType" in="${flash.assessmentTypes}">
<li><g:checkbox name="assessmentType" value="${assessmentType.id}" />${assessmentType.name}</li>
</g:each>
No problem...
Use a flow initializer to act as the first step in the flow and then move it to the first step on success of the initFlow.
def wizardFlow = {
initFlow {
flow.assessmentTypes = AssessmentType.list(); //<-- put them in the flow so you can access it in step1.gsp
}
on('success').to('step1')
on(Exception).to('handleFlowError')
step1{
on('next'){
flow.asessmentType = AssessmentType.get(params.assessmentType.id);
println("They picked ${flow.asessmentType}.");
}.to('step2')
on('exit').to('exit')
}
step2{
on('next'){ /* do stuff */ }.to('finish')
on('previous').to('step1')
on('exit').to('exit')
}
exit( /* exit flow before finish */ )
finish( /* finish up */ )
handleFlowError( */ not good :( */)
}
step1 GSP....
<g:select name="assessmentType.id" from="${assessmentTypes}" optionKey="id" value="${assessmentType?.id}" />
This is untested but it should work just fine. Enjoy :)

Resources