i am using TypeSafe activator template as a basis for an app (play+reactivemongo+knockoutJS).
i am trying to create a user, and while doing it i want to validate that the country they provided is already in the DB. but due to the structure of the program, i am finding it hard to put in that validation.
code
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"))))
}
)
}
}
my problem is to-fold: i need to verify the country exists in the DB, and i need to get the country for creating the User (which is an async action).
my best idea is to have UserForm implement something that provides a 'fold' method (as in Json...fold), so i can return invalid if the country is not found. if i know it exists, it's probably easier building the MongoDB query, awaiting it and doing a .get on the Option, as i already know it exists.
hope i made myself clear.
any ideas?
[edit] accepted suggestion below, with some changes: you gave me the direction, but i modified it a bit: i changed the UserForm class to take a Country as a parameter instead of a [string] country name. figured i would pass the list to the template which will render to a list, and the selected Country will be JSONed and uploaded as is (Country has a json.format).
i created exists(c: Country) method in CountryDao, which just does a find to the DB and returns the result.
then, i changed the saveUser as such:
...
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"))))
}
}
}
and it compiles. let's see if it works too :)
anyway, i think that resolved it for now. thank you mantithetical
One option is to do something like the following:
You could modify your
toUser
function to take an argument country of typeCountry
if you didn't want to look up country twice.