Get Grails to generate relative path in its relative URL - url

I have a web application that can be accessed either directly as http://host.foo.loc:8080/foo/ or via a secure reverse proxy as http://www.company.com/apps/foo/
By default, Grails will generate relative URLs with relative paths, for example:
<g:form action="bar">
will produce:
<form action="/foo/bar" method="post" >
This will be OK locally but the reverse proxy will not accept http://www.company.com/foo/bar (it's missing /apps/)
If I do:
<g:form action="bar" base=".">
it's fine. But I don't really want to specify it on each and every tag that generates a link.
The best way to deal with this would be to get Grails to generate relative paths in its relative URLs. Alternatively, I could live with setting a global "baseUrl" to "." but I don't know how to do that either.
Any idea ?
[edit] In fact, setting the "base" to "." doesn't work. The first page "/foo/controller/action" will generate the link as "./controller/nextaction" which the browser will translate as "/foo/controller/controller/action" => 404. I guess this is why they're using absolute paths: they're not paths.

I've never been able to make this kind of scenario work, so I always keep the proxied and unproxied context paths the same, i.e. I would put the app at http://host.foo.loc:8080/apps/foo. You can have a multi-level context path like this in Tomcat by naming the WAR file apps#foo.war.

Add grails.app.context = "/foo/bar" to your Config.groovy.

Related

What is the proper way to set up resource URLs in a ClojureScript single page application

I am developing a Clojure/ClojureScript SPA based on http-kit, compojure and tiny bits of hiccup on backend and mainly reagent on frontend. Project is done with leiningen, based on hand-wrecked chestnut template.
When I tried to make more complex URLs than just "/" the following setup created a mess for me:
When producing the initial hiccup to serve HTML and adding includes for CSS and JS files I followed the examples and added them as relative urls like
(include-css "css/style.css")
;and
(include-js "js/compiled/out/goog/base.js")
(include-js "js/compiled/myproject.js")
(note absence of slash in the beginning)
In the chestnut template I got default :asset-path option for cljsbuild set to "js/compiled/out"
Of course, when I tried to add a route to the same page with the http://my-domain/something URL in addition to root http://my-domain/ and load it, the thing failed to get any of my assets (trying to fetch them under e.g. /something/js/compiled/myproject.js).
I was able to fix this issue for explicitly included assets by making those urls relative to root (prepending a slash to each of them). It left me with the same problem with the script tag with src="js/compiled/out/cljs_deps.js" injected by cljsbuild, but this one I fixed by making :asset-path relative to root as well.
It all seems to work properly now, but the fact that I had to make some head-scratching and a surprisingly large amount of googling to finally resolve this makes me feel this is not the default approach. Hence the questions:
Did I do the right thing by converting all asset urls to relative-to-root ones? (Keeping in mind that I'm working on an SPA)
If yes, why isn't this a default approach and why I keep seeing relative-to-current location URLs everywhere (including all the examples on the web as well as lein templates)?
Update:
The relevant part of my app's compojure routes looks like this:
(defroutes home-routes
(resources "/")
(GET "/" _
(friend/authenticated
(html-response
(app-page))))
(GET "/something*" _
(friend/authenticated
(html-response
(app-page)))))

Path-relative URIs for resource files VS routes that "look-like" sub-directories

I'm using the URL like web.com/sys/test, which is rewritten in nginx config to web.com?system=sys&id=test via rewrite ^/(\w+)/(\w+)$ /?system=$1&id=$2 break;.
Also, all my resource files have relative path.
Therefore I get error:
Unable to find web.com/sys/css/user.css, however user.css is located in /css/.
Is there a way to solve the problem remaining the relative path for resource files?
Used base tag:
<base href="/">
However, in some cases this method may just add a whole lot of new problems. Look at this link

Generate URL of resources that are handled by Grails AssetPipeline

I need to access a local JSON file. Since Grails 2.4 implements the AssetPipeline plugin by default, I saved my local JSON file at:
/grails-app/assets/javascript/vendor/me/json/local.json
Now what I need is to generate a URL to this JSON file, to be used as a function parameter on my JavaScript's $.getJSON() . I've tried using:
var URL.local = ""${ raw(asset.assetPath(src: "local.json")) }";
but it generates an invalid link:
console.log(URL.local);
// prints /project/assets/local.json
// instead of /project/assets/vendor/me/json/local.json
I also encountered the same scenario with images that are handled by AssetPipeline1.9.9— that are supposed to be inserted dynamically on the page. How can I generate the URL pointing this resource? I know, I can always provide a static String for the URL, but it seems there would be a more proper solution.
EDIT
I was asked if I could move the local JSON file directly under the assets/javascript root directory instead of placing it under a subdirectory to for an easier solution. I prefer not to, for organization purposes.
Have you tried asset.assetPath(src: "/me/json/local.json")
The assets plugin looks in all of the immediate children of assets/. Your local.json file would need to be placed in /project/assets/foo/ for your current code to pick it up.
Check out the relevant documentation here which contains an example.
The first level deep within the assets folder is simply used for organization purposes and can contain folders of any name you wish. File types also don't need to be in any specific folder. These folders are omitted from the URL mappings and relative path calculations.

Advantage of <h:graphicImage> over <img>

What are the advantages of using <h:graphiImage> over normal <img> (in terms of performance e.g. parse/render time, possible http caching if any?, etc.) for JSF2?
You don't get server-side attributes on <img> elements.
There is no safe and easy way to set an absolute path for the src attribute. This is important because you may well be referencing the same image from multiple pages that reside in different directories. Would you want the hassle of maintaining their relative location? Sure, you can use <img src="#{resource['images:myImage.png']}"/> to get a safe absolute path. Wouldn't it just be easier to use <h:graphicImage name="myImage.png" library="images"/>?
What's this about a "safe" absolute path?
You could leave your images outside the usual resources folder and specify them in an absolute path like this, for example: <img src="/myApp-web/faces/images/myImage.png"/> and that would work. But then what happens when you want to deploy your app? Do you want your URLs to be like http://www.mysite.com/faces/myPage.xhtml? Of course not. You want to set the context root to the server root. But you don't want the hassle of changing all your img tags for a production deployment, nor do you want some hack that involves getting the base URL from an application-scoped bean and hoping you remember to change a property for production deployment. So you're better off, at the very least, using <img src="#{resource['images:myImage.png']}"/> or the much easier to remember <h:graphicImage name="myImage.png" library="images"/>.

Grails g:link - include app name in resulting anchor href attribute

This GSP:
<g:link controller="book" action="show" id="5">Example</g:link>
results in this HTML:
Example
This is relative to the HTTP host. If your site is running at http://localhost:8080 that's fine.
During development, an app will more commonly be running at http://localhost:8080/appName.
In such cases, the above link will not work - it will result in an absolute URL of http://localhost:8080/book/show/5 instead of the required http://localhost:8080/appName/book/show/5
What changes are required of the above GSP for the app name to be present in the resulting anchor's href?
The configuration setting grails.app.context should be equal to the context where you want your application deployed. If it's not set, as in the default configuration, it defaults to your application name, like http://localhost:8080/appName. If you want to deploy your app in the root context (e.g. http://locahost:8080/), add this to your Config.groovy:
grails.app.context = "/"
If the context is properly set, the URLs generated by g:link tags will include the context before the controller name.
I found that the meta tag is very useful for getting information in GSP files.
For example, if you want your application name, you can get it like this:
<g:meta name="app.name"/>
You can get any property in your application.properties file like that.
And if you, like me, need to concatenate it to another value, here is my example. Remember that any tag can be used as a method without the g: namespace. For example:
<g:set var="help" value="http://localhost:8080/${meta(name:"app.name")}/help" />
Grails documentation about this is a little poor, but it is here.
For me the single best reason to use <g:link> is that it adds the context if there is one, or omits it if you're running at http://localhost:8080 or in prod at http://mycoolsite.com - it's trivial to just concatenate the parts together yourself otherwise.
The same goes for using g:resource with css, javascript, etc. - it lets you have one GSP that works regardless of what the context is (e.g. 'appName'), since it's resolved at runtime.
I think that is what grails.serverURL is for. You defined this config variable in the Config.groovy, check the configuration documentation for Grails for more details.
Hope this helps!
createLink tag includes your appname / context parameter automatically in the link.
Here is reference doc for it.

Resources