1

I am making a Clojure web-app to process numeric input data. I have set up the main page and am working on having the inputed data processed and displayed after submission via a button.

key bits of code with comments:

(defn process-grades 
      "Takes user input from home's form-to function and processes it into the final grades list"
      [weights grades]
    (->> grades
         (map (partial percentify-vector weights))  ;; <- The functions being called here are omitted but defined in the same name space.
         (mapv #(apply + %))))


    (defn home [& [weights grades error]]
  (html
    [:head
    [:title "Home | Clojuregrade"]]
    [:body
    [:h1 "Welcome to Clojuregrade"]
    [:p error]
    [:hr]
   (form-to [:post "/"]
    [:h3 "Enter the weights for each of the grades below. Of course, all of the numbers should add up to 100%. Be sure to include the brackets"
    [:br]
     (text-area {:cols 30 :placeholder "[40 10 50] <- adds up to 100%"} "weights" weights)]
    [:h3 "Enter ALL of the grades for EACH STUDENT in your class.
      Make sure that each of the grades is ordered such that the grade corresponds
      to its matching weight above."
    [:br]
    (text-area {:rows 15 :cols 30 :placeholder
"[89 78 63]
                    [78 91 60]
                    [87 65 79]
                    ... " } "grades" grades)]
     (submit-button "process"))]))

(defn processed [weights grades]
  (cond
   (empty? weights)
   (home weights grades "You forgot to add the weights!")
   (empty? grades)
   (home weights grades "You forgot to add the grades!")
  :else
  (do
  (html  
   [:h2 "These are your final grades."]
   [:hr]
   [:p "test"]))))  ;; <- I would like to call process-grades here. "test" renders fine. 

(defroutes app
  (GET "/" []
       {:status 200
        :headers {"Content-Type" "text/html"}
        :body (home)})
  (POST "/" [weights grades] (processed weights grades)) 
  (ANY "*" []
       (route/not-found (slurp (io/resource "404.html"))))) 

;; ... 
artem
  • 46,476
  • 8
  • 74
  • 78
kurofune
  • 1,055
  • 12
  • 26
  • Just a general idea for debugging. Did you check with firebug the post request? Are the values as expected? Did you check the generated html form? Does it look correct? Maybe there is just a simple syntax/spelling error somewhere. I am not familiar with hiccup, but i cannot see the "grades" input defined somewhere, maybe thats the problem? – sveri Feb 25 '14 at 11:13
  • I'll look into firebug, but no html is being rendered, only a 404 error page. I thought the weights and grades variables were being defined via the text area tags in the home function with "weights" weights and "grades" grades, but I must admit that this syntax befuddles. The hiccup docs are also less than informative and google searches turn up my question and blog outdated blog posts. In the compojure docs I saw something which I thought might be of use, but it is over my head [link](https://github.com/weavejester/compojure/wiki/Destructuring-Syntax) – kurofune Feb 25 '14 at 16:21
  • (POST "/" [weights grades] ...) looks incorrect to me. You have no parameters in your URI, it's just "/". If it is not getting hit, you are probably not actually sending a POST request to /. How are the weights and grades supposed to be extracted from the URI if there are no parameters? I think you might need to extract them from the request parameters instead of the URI. – foxdonut Feb 25 '14 at 17:25
  • It seems to me your question is "why do I get a 404 error?", not "do I need a database?" – Nathan Davis Feb 27 '14 at 02:38

2 Answers2

1

My Assumption was right. I was taking your code and put it into a barebone luminus project. The html your code produces looks like this:

<h3>

Enter the weights for each of the grades below. Of…
<br></br>
<textarea id="weights" placeholder="[40 10 50] <- adds up to 100%" name="weights" cols="30"></textarea>
</h3>
<h3>
Enter ALL of the grades for EACH STUDENT in your c…
<br></br>
<textarea id="grades" rows="15" placeholder="bla" name="grades" cols="30"></textarea>
</h3>

And here comes the error:

<form method="POST" action="/">
    <input type="submit" value="process"></input>
</form>

The form element has to wrap the input elements, otherwise it wont submit them as part of the request.

So if you take your hiccup code and change it to this:

(defn home [ & [weights grades error]]
  (html
    [:h1 "Welcome to Clojure-grade"]
    [:p error]
    [:hr]
    (form-to [:post "/"]
      [:h3 "Enter the weights for each of the grades below. Of course, all of the numbers should add up to 100%. Be sure to include the brackets"
     [:br]
     (text-area {:cols 30 :placeholder "[40 10 50] <- adds up to 100%"} "weights" weights)
     ]
    [:h3 "Enter ALL of the grades for EACH STUDENT in your class.
      Make sure that each of the grades is ordered such that the grade corresponds
      to its matching weight above."
     [:br]
     (text-area {:rows 15 :cols 30 :placeholder "bla"} "grades" grades)]
                                       ;...
                                       ;
                                       ;                                     (Each     grade corresponds to one of the weights above,
                                       ; so order is important. You can copy and paste directly from your excel file but don't forget
                                       ; the brackets!)" } "grades" grades)]
     (submit-button "process")))) ;; <- when I hit this in the browser I get a 404, with or without input.

It works. Take precise look at: "(form-to [:post "/"]". I moved it a few lines up so that it wraps the input elements.

Just a side note, spend some time working with the browser developer tools and read at least a small html tutorial. Especially knowing how to use the developert tools will give you a big edge while debugging such problems.

sveri
  • 1,372
  • 1
  • 13
  • 28
  • You were right about the form-to function but it is still not working. I think that I have a lot of troubleshooting to do before it actually runs. I started a thread in the google group [link](https://groups.google.com/forum/m/#!topic/compojure/BA_C9-FSMH8) because it seems to be getting too unwieldy for stack. – kurofune Feb 26 '14 at 07:38
  • 1
    Whatever you want :D I uploaded my working example here: https://github.com/sveri/grades You can check that out and run it with "lein ring server", proceed to localhost:3000/landing, enter your input and after you submit it you will see the data in the console output. Btw. using something like luminus will get you started much easier ;-) – sveri Feb 26 '14 at 08:27
  • I totally figured the routing out thanks to your last post. A few insights: (1) We can just make the GET "/landing" in defroutes simply "/" (2) My app was working from the clojuregrade.web namespace, the whole time. By adding a POST in my defroutes there I was able to duplicate what you did. (3) getting the input data-structure into something that is readable by the process-grades function is really tricky and will probably be a new question. I think I am done with this `lein new heroku` template. Luminus seems to be the new standard anyway and is much better documented. Thank you again! – kurofune Feb 26 '14 at 12:11
  • Yea, just generate a default site with luminus and go through the code, the important parts are easy to understand. Later you can still use the heroku template. If you grasped the basic parts you will see that luminus just composes itself of the "standard clojure web applications". – sveri Feb 26 '14 at 14:06
0

Where are weights and grades being passed into processed? I think you need to pass them as arguments if you want to use them:

(defn processed [weights grades]
  ;; .. snip
  )

;; .. snip

(POST "/" [weights grades] (processed weights grades))
d11wtq
  • 34,788
  • 19
  • 120
  • 195
  • I tried this out, but I am getting a 404 and it is accessing an html in another folder, meaning that it is skipping over the ` POST ` method altogether. I have also added some exception catching to the ` processed ` function to test whether or not it is even being called and changed the mathy bits to simply see if I could make it render text. Neither has worked. The home function is supposed to define the weights and grades variables from user inputs and then process them. I will edit the code above to show you everything in this file. Thank you for your help! – kurofune Feb 25 '14 at 06:55