5

I'm developing a web application with Clojure, currently with Ring, Moustache, Sandbar and Hiccup. I have a resource named job, and a route to show a particular step in a multi-step form for a particular job defined like this (other routes omitted for simplicity):

(def web-app
  (moustache/app
   ;; matches things like "/job/32/foo/bar"
   :get [["job" id & step]
         (fn [req] (web.controllers.job/show-job id step))]))

In the view my controller renders, there are links to other steps within the same job. At the moment, these urls are constructed by hand, e.g. (str "/job/" id step). I don't like that hard-coded "/job/" part of the url, because it repeats what I defined in the moustache route; if I change the route I need to change my controller, which is a tighter coupling than I care for.

I know that Rails' routing system has methods to generate urls from parameters, and I wish I had similar functionality, i.e. I wish I had a function url-for that I could call like this:

(url-for :job 32 "foo" "bar")
; => "/job/32/foo/bar"

Is there a Clojure web framework that makes this easy? If not, what are your thoughts on how this could be implemented?

Gert
  • 3,839
  • 19
  • 22

2 Answers2

4

Noir provides something similar. It's even called url-for.

Matthias Benkard
  • 15,497
  • 4
  • 39
  • 47
  • Nice one! I've looked at Noir a number of times, but so far I've really liked the more minimalist approach of Moustache. I will do a little experiment today to see if Noir suits my needs. – Gert Mar 13 '12 at 20:43
2

The example function you have mentioned could be implemented as below. But I am not sure if this is exactly what you are looking for.

(defn url-for [& rest]
    (reduce 
        #(str %1 "/" %2) "" (map #(if (keyword? %1) (name %1) (str %1)) rest)))
Ankur
  • 33,367
  • 2
  • 46
  • 72
  • Thanks, but this would essentially be the same as hard-coding the url, since this function will just translate :job into "/job/". – Gert Mar 13 '12 at 20:41