I'm trying to access methods from controllers in a local plugin. I included the plugin like so:
grails.plugin.location.'helloworld' = "../helloworld"
I want to invoke the hello() method and pass in some params to it. I tried the following from the index page of my app:
<g:include plugin="helloworld" action="index" controller="hello" model="['name':'John Doe']"></g:include>
Here is the controller method in the plugin:
package helloworld
class HelloController {
def index() {
println "working"
}
}
I'm trying to keep it simple and get it to work before I worry about rendering views and processing parameters. I'm sure my approach is not the right way, I just need someone to point me in the right direction please.
Try:
package helloworld
class HelloController {
def index() {
render "working"
}
}
Related
For Grails 2.3.3, it allows same name controller in different package with namespaced controller according to http://grails.org/doc/latest/guide/theWebLayer.html#namespacedControllers
So we have package like this:
/admin/FooController
/public/FooController
To keep consistent we want the view package like this:
/views/admin/foo/...
/views/public/foo/...
However, in the FooController action, if you don't hard code the render method. It will find the view in the
/views/foo/index....
It seems it can't take advantage of namespace. We have to hard code.
Anyone has good idea for that?
You can certainly do this. Take a look at this post by Sérgio Michels shows how to render views from different directories using afterInterceptor. The idea is to substitute the default view before its getting rendered.
So your controller will be something like this:
package test.xpublic
class FooController {
static namespace = 'public'
def afterInterceptor = { model, modelAndView ->
if (modelAndView.viewName.contains('index')) {
modelAndView.viewName = "/public/index"
}
}
def index() { }
}
You can be creative and make it smart to pick the right view, since afterInterceptor will be called for each action.
This will help you to render the view from your directory (views/admin or views/public). However, you also need to take care of the UrlMappings
class UrlMappings {
static mappings = {
"/foo/admin" {
controller="foo"
namespace = 'admin'
}
"/foo/public" {
controller="foo"
namespace = 'public'
}
...
}
and finally on the links you need to pass the namespace.
<g:link controller='foo' namespace="admin" >Admin</g:link>
<g:link controller='foo' namespace="xpublic">Public</g:link>
A sample application is provided here
At least with Grails 3.2.0 this is working out of the box. See http://docs.grails.org/latest/guide/theWebLayer.html#_selecting_views_for_namespaced_controllers for more details
I have a filter and the controllerName var getting controller target.
For example:
when user try to access /myApp/book/index, my filter is triggered and controllerName is equals book. How can I get a BookController instance?
Tks
EDIT:
I can get an Artefact using:
grailsApplication.getArtefactByLogicalPropertyName("Controller", "book")
But what I do with this artefact?
The controller will be registered as a spring bean. Just grab it by name:
applicationContext.getBean('mypackage.BookController') // or
def artefact = grailsApplication.getArtefactByLogicalPropertyName("Controller", "book")
applicationContext.getBean(artefact.clazz.name)
As Burt said, you probably don't want one controller instance inside your filter. This is a wrong way to solve your problem.
Grails Controllers as injected automagically by Spring Framework, and there is some black magic and procedures made when creating it. So, I can assure you this is not the way to solve this problem.
As you yourself described, you want to call your action, and I can imagine you're trying to reuse some code that resides in your action, maybe to generate some data in your database, or even to work with your HTTP session, am I right?
So, you can do two things to solve this kind of issue.
1) Just redirect your request flow to to your controller/action like this:
if (something) {
redirect controller: 'xpto', action: 'desired'
return false
}
2) Or you can get the logic inside your action (that is doing that dirty job you want to run), separate that logic inside one service, and reuse the service in both classes (action / service) this way:
MyService.groovy
class MyService {
def methodToReuse() {
(...)
}
}
MyController.groovy
class MyController {
def myService //auto-injected by the green elf
def myAction = {
myService.methodToReuse()
}
}
MyFilters.groovy
class MyFilters {
def myService //auto-injected by the red elf
(...)
myService.methodToReuse()
(...)
}
[]s,
You should be able to call newInstance on the artefact you've retrieved. newInstance works just like the constructor so you can provide any parameters you would to a normal constructor call.
So you can probably just do:
def bookController = grailsApplication.getArtefactByLogicalPropertyName("Controller", "book").newInstance()
Working code:
import org.codehaus.groovy.grails.web.context.ServletContextHolder
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
import org.springframework.context.ApplicationContext
ApplicationContext applicationContext = (ApplicationContext) ServletContextHolder.getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
def grailsApplication
String nameController = "search"
def artefact = grailsApplication.getArtefactByLogicalPropertyName("Controller", nameController)
def controller = applicationContext.getBean(artefact.clazz.name)
Im wondering if something like this is possbile:
abstract class AbstractController {
def list = {
//default list action
}
}
class MyController extends AbstractController {
def show = {
//show action
}
}
Where AbstractController is not visible on the web i.e /app/abstract/list is not accessible and where MyController has the actions list and show and is accessible on the web as /app/my/....
Anyone ever done anything like this?
Try putting AbstractController into src/groovy folder.
Though, sharing functionality over Controllers might be not the best idea - it's better to move it to POGO classes or services. This question covers this issue partially: How do you share common methods in different grails controllers?
For recent version of grails (3.x as the time of writing) it would be better to use trait instead of extending an abstract Controller or use Mixin, the later was deprecated since introducing traits in groovy v2.3, here is an example of using a trait to add a generic behaviors to your controller:
1- Create your traits in src/groovy, e.g.
import grails.web.Action
trait GenericController {
#Action
def test(){
render "${params}"
}
}
2- Implement your trait as you implement any interface:
class PersonController implements GenericController {
/*def test(){
render 'override the default action...'
}*/
}
Note: traits can dynamically access all controller objects: params, response... and so on, and you still can override trait's action.
Hope this help.
I'm pretty new to grails and spring
Me created a service like this
services\com.mypackage\MyService
where
class MyService {
static transactional = true
def serviceMethod(params) {
println "params:"+params
}
}
Then when in my controller
controller\com.mypackage\mycontroller
Then in its action I tried to access like this
def myaction= {
com.mypackag.MyService myService //also used def myService
myService.serviceMethod(params)
render(view: "otherpage")
}
But it show the following error :(
java.lang.NullPointerException: Cannot invoke method serviceMethod() on null object
it cannot make the object of myservice.
myService shows null
What mistake i have done?
It will be very helpful if anyone provide me some good simple links and tutorials for using service with grails
Thank you
One mistake you have done.
You are declaring that myService inside your myaction closures. Where it should be done in the controller outside any of your methods or closures.
You can access your service methods using your service object (here myService) inside any of your methods or closures
So change like this
In your controller\com.mypackage\mycontroller declare your service first
def myService
Then you can access it in any closures
def myaction= {
myService.serviceMethod(params)
render(view: "otherpage")
}
Your directory hierarchy does not correspond to you packages. You should change the directory hierarchy for your service to:
services\com\mypackage\MyService.groovy
and make sure you add the following at the top of MyService.groovy
package com.mypackage
class MyService {
// .....
}
Similarly, change the directory hierarchy for your controller to
controller\com\mypackage\MyController.groovy
Then to get a reference to your service inside your controller
// add the correct package statement
package com.mypackage
// rename the controller and the mycontroller.groovy file to MyController
class MyController {
// this will be injected by Spring (it must be named with a lower-case 'm')
def myService
def myaction= {
// use the service inside your action
myService.serviceMethod(params)
render(view: "otherpage")
}
}
1) I'd read the Grails User guide on Services
2) I'd make your services using the command line tools grails provides as it will save you putting things in invalid directories (com.mypackage as a folder name is going to give you nothing but trouble), and it will make sure you have the correct package declarations at the top of your groovy files
How do i find all the controllers running in an application ?
I am trying to create a menu using YUI where only registered controllers will have a menu shown. A controller class will create a static list with various properties detailing name, action, etc. (much like grails-nav plugin).
I want to create a taglib that can find all controllers, identify which ones have this static list then look into each list and build up a menu.
I think i can use ControllerGrailsClass.metaClass.hasProperty to identify whether a given controller has the static property - but how do I find all the Controller classes to interrogate ?
Thanks in advance
You can get a list from the GrailsApplication object. Example:
class TestController {
def grailsApplication // gets injected automatically
def test = {
grailsApplication.controllerClasses.each { controllerArtefact ->
def controllerClass = controllerArtefact.getClazz()
println "$controllerArtefact, $controllerClass"
}
}
}
If you're not in a controller, you can get a hold of the grails application object like so:
import org.codehaus.groovy.grails.commons.ApplicationHolder
def grailsApplication = ApplicationHolder.application