3

I recently started a new Grails project and I'm trying to use the scaffold feature as much as I can. I installed the templates with grails install-templates and modified them so they rely on the current controller if certain methods are available (for example, the show method would call the renderShow method if available).

The problem I have is that when that method is called from the scaffold template, it's not found hence an exception is thrown. If the same method is called from the actual controller, it works as expected.

What I'm missing?

To ilustrate the question, I created a small project. The interesting commit is this one: https://github.com/deigote/GrailsScaffoldingMethodCallProblem/commit/0fce966bad6e8004a7133511149c09de54be24bf

When running the app, if you go to the testDemoMethod (.../GrailsScaffoldingMethodCallProblem/demo/testDemoMethod) you "Hi, I'm a method" rendered, and the following is printed:

[public java.lang.Object grailsscaffoldingmethodcallproblem.DemoController.this$2$demoMethod()]

But if you go to the index (.../GrailsScaffoldingMethodCallProblem/demo/testDemoMethod) an empty list is printed and I obtain an exception:

Message: No signature of method: grailsscaffoldingmethodcallproblem.DemoController.demoMethod() is applicable for argument types: () values: []
   Line | Method
->>  11 | index    in grailsscaffoldingmethodcallproblem.DemoController

Any clue why is this happening or how to get around it?

Edit: Ian Robert's answer solved the question: Controller method not found if called from scaffolding template

Community
  • 1
  • 1
Deigote
  • 1,721
  • 14
  • 15

1 Answers1

2

Because this within the scaffolding template does not refer to the controller class that declares the static scaffold = true. When you use runtime dynamic scaffolding in a controller class A the scaffolding template is used to generate a separate class (call it B, though in fact it will probably have the same name as A but be loaded via a different classloader) and each instance of A will delegate to an instance of B any actions that B defines but A does not explicitly override.

If you need to get at the real controller instance from inside the scaffolded code you'll probably have to use a trick like

import grails.util.GrailsWebUtil
...
def index() { 
    def realController = GrailsWebUtil.getControllerFromRequest(request)
    println realController.respondsTo('demoMethod')  
    realController.demoMethod() 
    redirect(action: "list", params: params) 
}
Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • That dit the trick, many thanks! I thought that the scaffolded stuff could be in another class, but the class name was the same and I didn't think about the classloader possibility. Very clever :-)! I'd vote you up but it seems I don't have enough reputation :-(. Thanks again. – Deigote May 02 '13 at 13:00
  • @Deigote you can _accept_ the answer by clicking on the tick mark to the left, which in itself will give you +2 rep. It shouldn't take you long to get the first few privileges. – Ian Roberts May 02 '13 at 13:16
  • since the question was voted up by a few people, I got enough reputation to vote you up - then stackoverflow itself warned me about the "accept the answer" thing. So I already did both things. Thanks again :)! – Deigote May 03 '13 at 06:42