Clojure/compojure: Как вы обрабатываете пользовательский ввод из веб-формы?

Я делаю веб-приложение Clojure для обработки числовых входных данных. Я настроил главную страницу и работаю над тем, чтобы вводимые данные обрабатывались и отображались после отправки с помощью кнопки.

ключевые фрагменты кода с комментариями:

(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"))))) 

;; ... 

2 ответа

Решение

Мое предположение было правильным. Я взял твой код и вложил его в голый проект Luminus. HTML-код, который создает ваш код, выглядит следующим образом:

<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>

И тут появляется ошибка:

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

Элемент формы должен обернуть входные элементы, иначе он не будет отправлять их как часть запроса.

Так что, если вы возьмете код сбоя и измените его следующим образом:

(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.

Оно работает. Внимательно посмотрите на: "(form-to [:post "/"]". Я переместил его на несколько строк вверх, чтобы обернуть входные элементы.

Просто примечание, потратьте некоторое время на работу с инструментами разработчика браузера и прочитайте хотя бы небольшой учебник по HTML. Особенно знание того, как использовать инструменты developer t, даст вам большое преимущество при устранении таких проблем.

Где weights а также grades будучи переданным в processed? Я думаю, что вам нужно передать их в качестве аргументов, если вы хотите их использовать:

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

;; .. snip

(POST "/" [weights grades] (processed weights grades))
Другие вопросы по тегам