6

I have static method in a domain class that returns a url. I need to build that url dynamically but g.link isn't working.

static Map options() {
    // ...
    def url = g.link( controller: "Foo", action: "bar" )
    // ...
}

I get the following errors:

Apparent variable 'g' was found in a static scope but doesn't refer to a local variable, static field or class. Possible causes:
You attempted to reference a variable in the binding or an instance variable from a static context.
You misspelled a classname or statically imported field. Please check the spelling.
You attempted to use a method 'g' but left out brackets in a place not allowed by the grammar.
 @ line 17, column 19.
           def url = g.link( controller: "Foo", action: "bar" )
                     ^

1 error

Obviously my problem is that I am trying to access g from static context, so how do I get around this?

tim_yates
  • 167,322
  • 27
  • 342
  • 338
ubiquibacon
  • 10,451
  • 28
  • 109
  • 179

2 Answers2

9

The g object is a taglib, which is not available inside a domain class like it would be in a controller. You can get at it through the grailsApplication as shown here: How To Call A Taglib As A Function In A Domain Class

A better way to do this in Grails 2+ is through the grailsLinkGenerator service, like so:

def grailsLinkGenerator

def someMethod() {
    def url = grailsLinkGenerator.link(controller: 'foo', action: 'bar')
}

In both cases, you'll need to do some extra work to get grailsApplication/grailsLinkGenerator from a static context. The best way is probably to grab it off the domainClass property of your domain class:

def grailsApplication = new MyDomain().domainClass.grailsApplication
def grailsLinkGenerator = new MyDomain().domainClass.grailsApplication.mainContext.grailsLinkGenerator
Community
  • 1
  • 1
ataylor
  • 64,891
  • 24
  • 161
  • 189
  • I was so close. I did try linkGenerator, but I was getting static context warnings. Grabbing it off the domain class as you suggested worked good. Thanks! – ubiquibacon Jun 25 '12 at 19:43
6

If you're using Grails 2.x you can use the LinkGenerator API. Here's an example, I am re-using a domain class I was testing with earlier so ignore the non-url related functionality.

class Parent {
    String pName

    static hasMany = [children:Child]

    static constraints = {
    }
    static transients = ['grailsLinkGenerator']

    static Map options() {
        def linkGen = ContextUtil.getLinkGenerator();
        return ['url':linkGen.link(controller: 'test', action: 'index')]
    }
}

Utility Class with Static Method

@Singleton
class ContextUtil implements ApplicationContextAware {
    private ApplicationContext context

    void setApplicationContext(ApplicationContext context) {
        this.context = context
    }

    static LinkGenerator getLinkGenerator() {
        getInstance().context.getBean("grailsLinkGenerator")
    }

}

Bean Def for New Utility Bean

beans = {
    contextUtil(ContextUtil) { bean ->
        bean.factoryMethod = 'getInstance'
    }
}

If you need the base URL, add absolute:true to the link call.

chrislatimer
  • 3,560
  • 17
  • 19