Grails 2.3.3 namespaced controller render view - grails

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

Related

Grails Local Plugin Render

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"
}
}

Reusable Grails controller helper methods

How to create reusable Grails controller helper methods which can be used in many controllers?
Right not I have few private methods in one controller. I want to share them with other controllers.
I would like have access to params, redirect etc.
The correct way to share code between controllers is to abstract the logic into a service. See
http://grails.org/doc/latest/guide/services.html
Note that if the service is not required to be transactional you should mark it as such.
If however you have web related logic (such as writing templates or markup to the output stream) then you can also use tag libraries to share logic, as tags can be invoked from controllers. See:
http://grails.org/doc/latest/guide/theWebLayer.html#tagsAsMethodCalls
You can use Mixins to you put all your common code:
// File: src/groovy/com/example/MyMixin.groovy
class MyMixin {
private render401Error() {
response.status = 401
def map = [:]
map.message = "Authentication failed"
render map as JSON
}
}
Now in a controller you can do something like this:
// File: grails-app/controller/com/example/OneController.groovy
#Mixin(MyMixin)
class OneController {
public someAction() {
if (!user.isAuthenticated) {
// Here we're using the method from the mixin
return render401Error()
}
}
}
Just one final advice: Mixins are applied during runtime so there is a little overhead.
The simplest answer is to create a class in src with a bunch of static methods and pass everything around as parameters, see: http://grails.org/doc/2.3.8/guide/single.html#conventionOverConfiguration
...or else create a controller base class that all other controllers extend from?
That said, I wonder if you are actually looking for scoped services? See http://ldaley.com/post/436635056/scoped-services-proxies-in-grails.

Grails: how to get a controller by controllerName in a filter?

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)

Is it possible to create a controller that extends an abstract controller in grails?

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.

Finding all controllers in application

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

Resources