我会将Questions 嵌套在Quiz 中,将QuestionOptions 嵌套在Question 中。这最终可能会使它更加紧凑。
case class Quiz(id: Int, name: String, questions: List[Question])
case class Question(id: Int, quizId: Int, title: String, options: List[QuestionOption])
case class QuestionOption(id: Int, questionId: Int, name: String)
Form 的可能实现将使用 lists 的 mapping:
val quizForm: Form[Quiz] = Form {
mapping(
"id" -> number,
"name" -> nonEmptyText,
"questions" -> list(mapping(
"id" -> number,
"quizId" -> number,
"title" -> nonEmptyText,
"options" -> list(mapping(
"id" -> number,
"questionId" -> number,
"name" -> nonEmptyText
)(QuestionOption.apply)(QuestionOption.unapply))
)(Question.apply)(Question.unapply))
)(Quiz.apply)(Quiz.unapply)
}
最冗长的部分是 HTML 表单,它需要包含所有这些字段。以下是表单将发送的数据示例(一个问题,多个答案)。
val data = Map(
"id" -> "1",
"name" -> "My Quiz",
"questions[0].id" -> "1",
"questions[0].quizId" -> "1",
"questions[0].title" -> "What?",
"questions[0].options[0].id" -> "1",
"questions[0].options[0].questionId" -> "1",
"questions[0].options[0].name" -> "red",
"questions[0].options[1].id" -> "2",
"questions[0].options[1].questionId" -> "1",
"questions[0].options[1].name" -> "green",
"questions[0].options[2].id" -> "4",
"questions[0].options[2].questionId" -> "1",
"questions[0].options[2].name" -> "blue"
)
每个问题元数据/答案的name 字段都需要具有将它们绑定在一起的唯一索引。这是一个粗略的例子:
<input type="hidden" name="id" value="1">
<input type="hidden" name="name" value="My Quiz">
<input type="hidden" name="questions[0].id" value="1">
<input type="hidden" name="questions[0].quizId" value="1">
<input type="hidden" name="questions[0].title" value="What?">
<input type="hidden" name="questions[0].options[0].id" value="1">
<input type="hidden" name="questions[0].options[0].questionId" value="1">
<input type="checkbox" name="questions[0].options[0].name" value="red">
<input type="hidden" name="questions[0].options[1].id" value="2">
<input type="hidden" name="questions[0].options[1].questionId" value="1">
<input type="checkbox" name="questions[0].options[1].name" value="green">
<input type="hidden" name="questions[0].options[2].id" value="3">
<input type="hidden" name="questions[0].options[2].questionId" value="1">
<input type="checkbox" name="questions[0].options[2].name" value="blue">
<input type="hidden" name="questions[0].options[3].id" value="4">
<input type="hidden" name="questions[0].options[3].questionId" value="1">
<input type="checkbox" name="questions[0].options[3].name" value="orange">
我们可以通过删除一些标题/名称字段并在Form 中忽略它们来缩小它,因为它们对持久性无关紧要。但这很快就会变得相当冗长。
此时我通常会放弃 Forms 并使用纯 JavaScript,因为 JSON 更易于处理(在我看来,可读性更强)。