如何在用作表单的case类中实现验证(使用Json.fromJson)

时间:2013-12-03 06:43:33

标签: json mongodb scala playframework-2.0 reactivemongo

我正在使用TypeSafe激活器模板作为应用程序的基础(play + reactivemongo + knockoutJS)。

我正在尝试创建一个用户,在执行此操作时,我想验证他们提供的国家/地区已经在数据库中。但是由于程序的结构,我发现很难进行验证。

Object UserContoller extends Controller {
  case class UserForm(
      firstName: String, 
      midName: Option[String], 
      lastName: String, 
      addr1: String,
      addr2: Option[String],
      addr3: Option[String],
      city: String,
      state: Option[String],
      zip: String, 
      country: String,
      email: String,
      phone: String
      ) {

    def toUser: User = User(
      BSONObjectID.generate, 
      Name(firstName, midName, lastName), 
      Vector(Email(email)), 
      Vector(Phone(phone)), 
      Address(addr1, addr2, addr3, city, state, zip, CountryDao.find(country))
    )
  }

  implicit val userFormFormat = Json.format[UserForm]

  def save = Action(parse.json) { req =>
    Json.fromJson[UserForm](req.body).fold(
      invalid => {
        BadRequest("Bad form").flashing(Flash(Map("errors" -> JsError(invalid).toString)))
      },
      form => Async {
        UserDao.save(form.toUser).map(_ => Created.flashing(Flash(Map("result" -> "success"))))
      }
    )
  }
}

我的问题是弃用:我需要验证数据库中是否存在国家/地区,我需要获取国家/地区来创建用户(这是异步操作)。

我最好的想法是让UserForm实现一些提供“折叠”方法的东西(如Json ... fold),所以如果找不到国家,我可以返回无效。如果我知道它存在,可能更容易构建MongoDB查询,等待它并在选项上执行.get,因为我已经知道它存在。

希望我明白自己。

任何想法?

[编辑] 接受以下建议,但有一些变化: 你给了我方向,但我修改了一下: 我更改了UserForm类,将Country作为参数而不是[string]国家/地区名称。想通知我会将列表传递给将呈现给列表的模板,所选的国家/地区将被JSON化并按原样上传(国家/地区有json.format)。

我在CountryDao中创建了exists(c:Country)方法,它只对数据库进行查找并返回结果。

然后,我改变了saveUser:

...
      form => Async {
        CountryDao.exists(form.country) match {
          case c if c==true => {
            UserDao.save(form.toUser map {_ => 
              Created.flashing(Flash(Map("result" -> "success")))
            }          
          }
          case c if c==false => {
            Future(BadRequest("Invalid Country").flashing(
              Flash(Map("errors" -> "Invalid Country"))))
          }
        }
      }

并编译。让我们看看它是否也有效:)

无论如何,我认为现在解决了这个问题。谢谢mantithetical

1 个答案:

答案 0 :(得分:1)

一种选择是执行以下操作:

def save = Action(parse.json) { req =>
  Json.fromJson[UserForm](req.body).fold(
    invalid => {
      BadRequest("Bad form").flashing(Flash(Map("errors" -> JsError(invalid).toString)))
    },
    form => Async {
      CountryDao.find(form.country).map { c => // assuming find returns an Option
        UserDao.save(form.toUser(c) /* or form.toUser() */).map(
          _ => Created.flashing(Flash(Map("result" -> "success"))))
      }.getOrElse(
          BadRequest("Invalid Country").flashing(
            Flash(Map("errors" -> "Invalid Country")))) // or something else more appropriate
    }
  )
}

如果您不想两次查找国家/地区,则可以修改toUser函数以获取Country类型的参数国家/地区。

def toUser (country: Country): User = User(
  BSONObjectID.generate, 
  Name(firstName, midName, lastName), 
  Vector(Email(email)), 
  Vector(Phone(phone)), 
  Address(addr1, addr2, addr3, city, state, zip, country)
)