Grails
  1. Grails
  2. GRAILS-2605

Cannot access createLink() from a service

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Duplicate
    • Affects Version/s: None
    • Fix Version/s: 1.4-M1
    • Component/s: Services
    • Labels:
      None

      Description

      Looks like createLink() is limited to the scope of controller/GSP/taglib (anything with a request). But it is a useful general-purpose tool, and there is really nothing specific to a request object required.

      e.g. in a MailService, you may want to embed links in the email, and createLink() /createLinkTo() is the obvious choice to do that.

      In short, createLink/createLinkTo() should be available in global scope.

        Activity

        Hide
        Torsten Curdt added a comment -

        This sucks badly. Why on earth does createLink() need a request??

        Show
        Torsten Curdt added a comment - This sucks badly. Why on earth does createLink() need a request??
        Hide
        B.Skerlecz added a comment -

        "workaround"

        class RegService {

        def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()

        def reg(def regInfo) =

        { def regPath = g.createLink(controller: 'registration', action: 'complete', params: ['id': regInfo.registrationId]) // ... }

        }

        Show
        B.Skerlecz added a comment - "workaround" class RegService { def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib() def reg(def regInfo) = { def regPath = g.createLink(controller: 'registration', action: 'complete', params: ['id': regInfo.registrationId]) // ... } }
        Hide
        Ryan Schneider added a comment -

        I tried the workaround by B. Skerlecz and it gives us the Context root and everything to the right of the URL, unfortunately it does not supply the stuff on the left that is needed for a full URL if you need an absolute link (protocol, server name, and port number).

        Show
        Ryan Schneider added a comment - I tried the workaround by B. Skerlecz and it gives us the Context root and everything to the right of the URL, unfortunately it does not supply the stuff on the left that is needed for a full URL if you need an absolute link (protocol, server name, and port number).
        Hide
        Graeme Rocher added a comment -

        There is no scope / time to resolve these remaining lower priority issues for 1.2 so moving to 1.3

        for 1.2 final only issues considered blocking will now be fixed

        Show
        Graeme Rocher added a comment - There is no scope / time to resolve these remaining lower priority issues for 1.2 so moving to 1.3 for 1.2 final only issues considered blocking will now be fixed
        Hide
        Patrick Jungermann added a comment -

        We had have the same issue for a while. We used a Job that uses a method of a Service to send HTML and plain text emails to our users, which contain generated links. The convenient way to use TagLibs in Service would be to create an instance of the requested one or by using the related beans. The main issue here is that you need a request bound to your context, if you want to use TagLib functionalities like createLink(). To handle this, we had used the following workaround within our Job (the locale part and logging is optional):

        // set mock request
        def ctx = ServletContextHolder.getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
        def webRequest = GrailsWebUtil.bindMockWebRequest(ctx)
        if (log.isInfoEnabled()) {
            log.info "dummy request bound to job thread"
        }
        
        // set locale
        def request = webRequest.getCurrentRequest()
        request.addPreferredLocale(Locale.GERMANY)
        if (log.isInfoEnabled()) {
            log.info "preferred locale for the request set to ${Locale.GERMANY}"
        }
        

        With this mock request bound, you could generate URLs without any problems.

        Show
        Patrick Jungermann added a comment - We had have the same issue for a while. We used a Job that uses a method of a Service to send HTML and plain text emails to our users, which contain generated links. The convenient way to use TagLibs in Service would be to create an instance of the requested one or by using the related beans. The main issue here is that you need a request bound to your context, if you want to use TagLib functionalities like createLink() . To handle this, we had used the following workaround within our Job (the locale part and logging is optional): // set mock request def ctx = ServletContextHolder.getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT) def webRequest = GrailsWebUtil.bindMockWebRequest(ctx) if (log.isInfoEnabled()) { log.info "dummy request bound to job thread" } // set locale def request = webRequest.getCurrentRequest() request.addPreferredLocale(Locale.GERMANY) if (log.isInfoEnabled()) { log.info "preferred locale for the request set to ${Locale.GERMANY}" } With this mock request bound, you could generate URLs without any problems.
        Hide
        Steve Shucker added a comment -

        you need to add 'org.springframework:spring-test:3.0.3.RELEASE' to your dependencies in buildconfig.groovy to make this work

        Show
        Steve Shucker added a comment - you need to add 'org.springframework:spring-test:3.0.3.RELEASE' to your dependencies in buildconfig.groovy to make this work
        Hide
        Matt Lachman added a comment -

        Steve, can you clarify? I'm not seeing how including a dependency would alter the fundamental behavior of createLink() and createLinkTo() requiring a request object.

        Show
        Matt Lachman added a comment - Steve, can you clarify? I'm not seeing how including a dependency would alter the fundamental behavior of createLink() and createLinkTo() requiring a request object.
        Hide
        Luke Daley added a comment -

        Matt,

        The spring-test module is not included by default in a WAR deployment, which means that `GrailsWebUtil.bindMockWebRequest()` will fail in a deployment (but will work in development) unless you explicitly bring in this dependency.

        Show
        Luke Daley added a comment - Matt, The spring-test module is not included by default in a WAR deployment, which means that `GrailsWebUtil.bindMockWebRequest()` will fail in a deployment (but will work in development) unless you explicitly bring in this dependency.
        Hide
        Graeme Rocher added a comment -

        Fixed as of the new LinkGenerator bean implemented by GRAILS-6685

        Show
        Graeme Rocher added a comment - Fixed as of the new LinkGenerator bean implemented by GRAILS-6685

          People

          • Assignee:
            Graeme Rocher
            Reporter:
            Jason Morris
          • Votes:
            15 Vote for this issue
            Watchers:
            15 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development