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