Compojure Lib-Noir session/put! unbound var error - clojure

I am converting an older web app I made a few months ago from Noir to Compojure and I am using the Lib-Noir add-on. It appears that session/put! is either changed in some way I don't understand or it is bugging out for whatever reason.
Here, I can see that 4Clojure appears to be using it with no problems: See Line 51. I also found this thread that covers the same question but there doesn't appear to be a satisfactory response.
This should work (Noir):
user=> (require '[noir.session :as sesh])
nil
user=> (sesh/put! :user "me")
ClassCastException clojure.lang.Var$Unbound cannot be cast to clojure.lang.Atom
clojure.core/swap! (core.clj:2162)
The above is the same error that I am looking at on the webpage. Basically I'm stuck.
Edit to add
Appears I created a bit of confusion with the command line part: (put!) is not working in the program either. There's not much to write about it, except that it is (shesh/put! :uname user) and it appears that :uname isn't working. I'm confused as to why it would have worked before and not now when I am using the same tools as before. This is a rewrite of a site I build about 6 months ago. I'm just moving it to Compojure from Noir. The lib-noir session is, as far as I know, essentially the same as what was in Noir.
ANOTHER EDIT
I put the code up on github. This isn't the completed project, but hopefully someone can decipher what is going on here: https://github.com/dt1/SoloResume

If you run it from the REPL, there is no browser session registered in Noir. You can simulate this by using binding:
(binding [sesh/*noir-session* (atom {:somekey "somevalue"})]
(sesh/put! :user "borkdude"))
Use this only for testing/simulating to see what goes on in the session map, not in production code.

A fairly old question, but answering here as it was the first Google result when I had the same problem. I was using compojure:1.1.6, ring:1.2.1 and lib-noir:0.7.6
You need to use noir.session/wrap-noir-session when defining your app - e.g:
(def app
(-> (handler/site (routes app-routes ))
session/wrap-noir-session
wrap-base-url))
References:
https://groups.google.com/d/msg/clojure/XXgSGhF912I/luhN9wmMoi8J

Related

how to set and get cookie with compojure?

Created project using lein new compojure project-name and have the server referencing (wrap-defaults project-name site-defaults).
Inside my handler I am calling controllers and passing the params to those controllers. Project structure:
handler.clj ;; ring accesses def app
controllers/app.clj ;; where route params are sent
example: (GET "/signup" {params :params} (controller-app/signup params))
So the issue I am having is I cannot figure out how to get or set cookies from the controllers file. Things I have tried:
passing cookie as a param: {cookies :cookies}. I was able to view the default cookie but could not set any data.
Use cookie-response and cookie-request. Same problem of not being able to add to the cookie.
Using the :cookie in every route possible and getting nothing back.
Any help would be much appreciated. There is not much documentation on this so unfortunately the problem has taken a fair amount of time.
Finally was able to solve it by brute force. It's no joke when people say the documentation for Clojure is pretty sparse. A couple of notes on ring:
Sessions are not what you think of when you hear sessions. It's just a signed cookie and a poorly documented one at that. Just ignore it. The few tutorials I did find constantly misspoke and used "sessions" when they meant "signed cookie". The documentation even uses cookies and sessions interchangeably. Why? I have no idea as they are completely separate methods of storing data. Sessions are a server side in memory store and cookies are a client side browser store.
:headers are needed otherwise the cookie will just download into an empty text file. Took forever to find out why this was the case.
:path has to go into the cookie body otherwise the cookie will only persist for the page where the cookie was set. You would think :path would go after :cookies and above :body. It makes no sense to me why the :path would be included in the hashmap along with the value. Again, no documentation for how or why so this took forever as well.
Now onto how to do this:
Here you pass the cookie to the controller from inside your handler. Cookies are available by default if you used "lein new compojure app-name" to create your app. I had to read the source code to figure this out.
default namespace (app-name/handler.clj) -
(ns some-namespace.handler
[compojure.core :refer :all]
[compojure.route :as route]
[ring.middleware.defaults :refer [wrap-defaults site-defaults]
[app-name.controllers.home :as home-controller))
Your app routes (app-name/handler.clj) -
(defroutes app-routes
(GET "/" {cookies :cookie} (home-controller/home cookies)))
Here is how you set the cookie itself (app-name/controllers/home.clj).
(ns app-name.controllers.home)
(defn home [cookies]
{:headers {"Content-Type" "Set-Cookie"},
:cookies {"cookie-name" {:value "cookie-value", :path "/"}},
:body "setting a cookie"})
Bottom of handler.clj using default wraps for specified routes (app-name/handler.clj)
(def app
(wrap-defaults app-routes site-defaults ))
This was a very simple problem that turned out to be far more complex. It took me 3 days to figure all of the above out. I am new to Clojure/Ring/Compojure but this has been the worst experience I have had yet programming.
It's really a problem of just enough abstraction to become dangerous (so basically nothing is obvious). Libraries like Ring REALLY need to be better documented and over explained if wider adoption is wanted.
Anyways, I hope this helps someone.
I personally spent quite some time to making cookie reading work due to my poor understanding of destructuring in compojure.
After wrapping yout application with the wrap-cookies handler, you need to destructure cookies variable "the clojure way" and not "the compojure way" since the cookies map is not in the request params map.
Example that doesn't work :
(GET "/read-cookie" [cookies]
(let [name (get-in cookies ["name" :value] "")]
(if (empty? name)
(layout/common [:h1 "I don't read a cookie"])
(layout/common [:h1 (str "I read a cookie : " name)]))))
Example that works :
(GET "/read-cookie" {:keys [cookies]} ;; or {cookies :cookies}
(let [name (get-in cookies ["name" :value] "")]
(if (empty? name)
(layout/common [:h1 "I don't read a cookie"])
(layout/common [:h1 (str "I read a cookie : " name)]))))
Hope this helps,
Use wrap-cookie from ring this will add cookie key in your request map, more details are here, then with compjure you have access to the req map, and you can use it.
https://github.com/ring-clojure/ring/wiki/Cookies

printing list values using let in clojure

how can I print list elements using let keyword in clojure language?
(defn build-headline-keywords-item [es-client conf common-item headline]
(let [headline headline]
(println (:headline))
(es/upsert es-client conf (merge common-item{:source ["headline"]
:type ["headline"]
:keywords headline}))))
Alan's answer covers the important parts of how to use Clojure to do this.
I'll take a different path and ask about whether this is an issue with your environment. Are you working in a REPL? Or running things in some other way? What is the actual thing you are running or evaluating?
Maybe you are using an editor where the console output is going someplace you're not seeing? For example, in Emacs the console output may go to a buffer that is not visible.
If I understand you correctly, it should look more like this:
(defn build-headline-keywords-item
[es-client conf common-item headline]
(println headline)
... )
UPDATE:
If you are still having trouble, make a test file and remove bits one-by-one until you get something that works. Then add the bits back in one at a time to build up the whole problem. It will work:
Code:
(defn build-headline [a b c headline]
(println headline))
(build-headline 1 2 3 "Space Aliens Invade!")
Result:
> lein run
Space Aliens Invade!
Please also see the online book Clojure for the Brave & True
for more information.

How to access db.clj methods in core.cljs in clojure

I am trying to create a web app in clojure.
i have used clojurescript om and react.
there are two files core.cljs and db.clj.
core.cljs contains ui for login page and db.clj contains all database connections.
Now i am trying to call a db.clj method add-user[username password] in
core.cljs.
In db.clj
(defn add-user [username,password]
(sql/with-connection db
(sql/insert-values :users [:username :password]
[username password])))
In core.cljs
(dom/button #js {:ref "submit"
:onClick (fn[e](add-user usname passwrd))}"submit")
But i am not able to call that method in core.cljs.
It shows some error message like
clojure.lang.ExceptionInfo : failed compiling file:src\login_page\core.cljs
clojure.lang.ExceptionInfo : No such namespace: login_page.db, could not locate login_page/db.cljs, login_page/db.cljc, or Closure namespace "login_page.db"
Rename db.clj to either db.cljs or db.cljc. That should get you past the 'No such namespace' error message.
That's the basic gist of it. Of course your dependencies on clj libraries will have to be removed - that might be the reason for the negative comment below. Alter your code so that you use a simple atom as your database. That should get you developing.
And you can wait for a much better answer than this one that will show you how to get the Client and Server communication setup. But it may not come because, as pointed out in the comments, there is already documentation for this, and unfortunately quite a few choices that have to be made. Another unfortunate thing is that the way to do it now may not be the way to do it early next year. Watch the Om-Next space!
I've never had any problems compiling .cljs or .cljc files. You just have to set up your lein project.clj file properly. There will be plenty of examples if you Google around, or you can take a look at the following small Github project: https://github.com/chrismurrph/passing-time - no need to worry about the code, just look at its project.clj file.

metrics clojure ring middleware not recording metrics

In my handler I have the following defined:
(def reg (new-registry))
(def app (-> app-routes
(expose-metrics-as-json)
(instrument reg)))
If I go to /metrics I only see an empty json object. What am I missing? Also, the documetation is not clear as to how I can report on the console, it seems report-to-console which is in the documentation is not used any more, instead there are reporters but I cannot find any documentation as to how you use reporters.
EDIT:
I have seen that metrics are being added and recorded by looking at this:
(meters/rates ((all-metrics reg) "ring.responses.rate.2xx"))
And the results are as expected, something like:
{1 0.06325196458537237, 5 0.01824839591203641, 15 0.006466051961211013, :total 6}
So it seems that although expose-metrics-as-json is creating an endpoint, the metrics are not getting added to it.
You are not passing the registry to expose-metrics-as-json. It falls back to the default registry.
In your threading expression, try changing the second line so that it reads:
(def app (-> app-routes
(expose-metrics-as-json "/metrics" reg)
(instrument reg)))
Ha! I found that this is actually a bug in the code. https://github.com/sjl/metrics-clojure/blob/master/metrics-clojure-ring/src/metrics/ring/expose.clj
([handler uri registry]
(expose-metrics-as-json handler uri default-registry {:pretty-print? false}))
This ignores the registry parameter. I got things to work by using
(expose-metrics-as-json "/metrics" reg {:pretty-print? false})
I will fix and create a pull request.

How do I compile Clojurescript forms from within Clojure?

I am using clj-webdriver to do some Selenium based testing on a Clojurescript web app. Sometimes, there is something in the app itself that I want to be able to fiddle with while the test are running. I see that clj-webdriver has something called (execute-script js args) that takes a string of Javascript code and runs it on the current testing browser. I have tested this and it seems to work. I would like to pass clojurescript code to execute-script though. I need something that will compile my Clojure form into Clojurescript code.
I see the following question that sort of relates. It says to use the js/emit function from clutch. I searched clutch and found it mentioned only in (view) in cljs-views.clj I have attempted the following in a repl:
user> (use 'com.ashafa.clutch.cljs-views)
nil
user> view
<core$comp$fn__4034 clojure.core$comp$fn__4034#ebd3f80>
user> js/emit
CompilerException java.lang.RuntimeException: No such namespace: js, #compiling (NO_SOURCE_PATH:1)
user>
This isn't terribly surprising, how could js be in a regular clojure namesapce? But how do I use this (or any other) system to generate Clojurescript (javascript) code that I can pass to execute-script?
Use the cljs.closure/build function:
(use '[cljs.closure :only [build]])
(build '(print "hello") {:optimizations :simple :pretty-print true})
There are more examples in a comment at the bottom of closure.clj. There are options for outputting to a file as well.