Play framework Leon Salat Model Form Mapping - mongodb

I'm creating a scala application using Play framework and mongoDB. I manage to have the connections up using Leon Play-Salat. I have a model
case class Person(
id: ObjectId = new ObjectId,
fname: String,
mname: String,
lname: String
)
In my controller I need to map it to a form
val personForm: Form[Person] = Form(
// Defines a mapping that will handle Contact values
mapping(
"id" -> of[ObjectId],
"fname" -> nonEmptyText,
"mname" -> text,
"lname" -> nonEmptyText
)(Person.apply)(Person.unapply))
How do I map the ObjectID to the form ? I'm getting error Object not found for the ObjectId.

Manage to get it working
val personForm: Form[Person] = Form(
// Defines a mapping that will handle Contact values
mapping(
"id" -> ignored(new ObjectId),
"fname" -> nonEmptyText,
"mname" -> text,
"lname" -> nonEmptyText
)(Person.apply)(Person.unapply))
I'm trying to do a CRUD function thus need the ID.

Found using own constructor and deconstructor is better
val personForm: Form[Person] = Form(
mapping(
"fname" -> nonEmptyText,
"mname" -> text,
"lname" -> nonEmptyText
)((fname, mname, lname) => Person(new ObjectId, fname, mname, lname))
((person: Person) => Some((person.fname, person.mname, person.lname))) )

Related

Validate scala forms, when form contains inner case classes

Help with Scala forms validation,
Here is the case class for the form data:
case class Data(
firstName: String,
lastName: String,
email: String,
confirm_email: String,
password: String,
confirm_password: String)
}
And the Scala Form:
val form = Form(
mapping(
"firstName" -> nonEmptyText,
"lastName" -> nonEmptyText,
"email" -> email,
"confirm_email" -> email,
"password" -> nonEmptyText(minLength = 8),
"confirm_password" -> nonEmptyText(minLength = 8))(Data.apply)(Data.unapply))
Now the problem is we need to validate the "email" and "confirm" email, but the problem is we need to create tuples or mapping. And so what is the best way to handle these kinds of form validation situations. It can be easily done by only using tuples and not mapping it to any case class.
But what can be done if we are requried to use mapping and case classes in forms.
First things first, I'd get rid of the confirm_email and confirm_password fields since they're redundant in the Data model. After this operation, it'll look like this:
case class Data(
firstName: String,
lastName: String,
email: String,
password: String)
Next, your form mapping needs to be updated:
val form = Form[Data](
mapping(
"firstName" -> nonEmptyText,
"lastName" -> nonEmptyText,
"email" -> tuple(
"email1" -> email,
"email2" -> email
).verifying(Messages("form.error.emailNotEquals"), email => email._1 == email._2),
"password" -> tuple(
"pass1" -> nonEmptyText(minLength = 8),
"pass2" -> nonEmptyText(minLength = 8)
).verifying(Messages("form.error.passwordNotEquals"), password => password._1 == password._2)
)((firstName, lastName, email, password) => Data(firstName, lastName, email._1, password._1))
((form: Data) => Some((form.firstName, form.lastName, (form.email, form.email), ("", ""))))
)
Two changes are required:
Nested mapping with validation both for email and password fields.
Custom apply and unapply method implementation in order to map the form with six fields into the models case class with four fields.
Notice that the custom unapply method doesn't set values for password fields since it's a desired behaviour in virtually all cases.
Finally, your view must be altered to refer new form tuple mapping correctly. For instance, fields for email should look as follows:
#helper.inputText(dataForm("email.email1"))
#helper.inputText(dataForm("email.email2"))
Fields which don't use new tuple mappings stay unchanged.

play framework how to reuse and extend a form mapping

I have a form mapping such as the following:
val myBaseMapping = mapping(
"email" -> email,
"password" -> text.verifying("Please provide a password", !_.isEmpty)
)(BaseModel.apply)(BaseModel.unapply)
This represents FormA. I have another form, FormB, that is identical but adds a couple more fields. This is what its mapping would look like:
val myExtendedMapping = mapping(
"email" -> email,
"password" -> text.verifying("Please provide a password", !_.isEmpty)
"name" -> text,
"website" -> text
)(ChildModel.apply)(ChildModel.unapply)
ChildModel extends BaseModel: it adds 2 new fields, name and website.
I am trying to code myExtendedMapping in such a way that I don't have to duplicate the binding definitions for the shared fields (email and password).
I am not sure what the Scala syntax would be here. I do not know how to 'extend' a given mapping and add bindings to it. Also, I'd prefer not to add ad-hoc verification because of the difference in behavior. Is this possible or do I just have to duplicate code?
What you can do is a simple composition. For example:
case class BaseModel(email: String, password: String)
case class ChildModel(name: String, website: String, base: BaseModel)
val commonMapping = mapping(
"email" -> email,
"passwod" -> texttext.verifying("Please provide a password", !_.isEmpty)
)(BaseModel.apply)(BaseModel.unapply)
val myExtendedForm = Form[ChildModel](mapping(
"name" -> text,
"website" -> text,
"base" -> commonMapping
)
((name, website, base) => ChildModel(name, website, base)) //bind
(child => Some(child.name, child.website, child.base)) //unbind
)

how can i get another form input verified in play?

This is my code based on the examples:
val signupForm = Form(
tuple(
"firstname" -> nonEmptyText,
"lastname" -> nonEmptyText,
"email" -> nonEmptyText,
"password1" -> nonEmptyText,
"password2" -> nonEmptyText,
"phone" -> optional(text)
) verifying ("That email address already exists please contact an administrator.", result => result match {
case (firstname, lastname, email, password1, password2, phone) => !User.checkexists(email).isDefined
})
)
but there is no example showing how i might add another check in there - say comparing the password1 & password2... or a third check...
where can i add another 'verifying ' bit?
thanks
val signupForm = Form(
tuple(
...
) verifying (...)
verifying (...)
verifying (...)
)
In your case:
val signupForm = Form(
tuple(
"firstname" -> nonEmptyText,
"lastname" -> nonEmptyText,
"email" -> nonEmptyText,
"password1" -> nonEmptyText,
"password2" -> nonEmptyText,
"phone" -> optional(text)
) verifying ("That email address already exists please contact an administrator.", result => result match {
case (firstname, lastname, email, password1, password2, phone) => !User.checkexists(email).isDefined
})
verifying (...)
)

How construct a one-to-many relationship form in Play with Scala and Slick?

Based on #JacobusR's answer how can I program a form in the controller that allows me to send it to the view as a Form type with all one-side table columns mapping and many-side table seq-mapping?
Something like this:
In the Controller
private val DirectorateAndItsServiceAreas: Form[???] = Form(
mapping(
"dirCode" -> nonEmptyText,
"name" -> text,
"serviceAreaRow" -> seq( /* don't have and don't want serviceAreasRow in Directorate table */
mapping(
"areaCode" -> nonEmptyText,
"dirCode" -> nonEmptyText,
"name" -> text
)(ServiceArea.apply)(ServiceArea.unapply)
)
)(Directorate.apply)(Directorate.unapply)
)
In the View
#(DirectorateAndItsServiceAreasForm: Form[Directorate/ServiceArea],...

How to correctly validate forms with Play! in Scala?

I'm brand new to Play!, and I'm trying to migrate my existing website from cakePHP to Play!.
The problem I'm facing is about form validation.
I defined a case class User, representing the users of my website :
case class User(
val id: Long,
val username: String,
val password: String,
val email: String
val created: Date)
(There are some more fields, but these ones suffice to explain my problem)
I would like my users to be able to create an account on my website, using a form, and I would like this form to be validated by Play!.
So, I created the following action :
def register = Action {
implicit request =>
val userForm = Form(
mapping(
"id" -> longNumber,
"username" -> nonEmptyText(8),
"password" -> nonEmptyText(5),
"email" -> email,
"created" -> date)(User.apply)(User.unapply))
val processedForm = userForm.bindFromRequest
processedForm.fold(hasErrors => BadRequest("Invalid submission"), success => {
Ok("Account registered.")
})
}
Obviously, I do not want the user to fill the id or the creation date by himself in the form. So my question is : what should I do ?
Should I define a new "transition model" containing only the fields that are actually provided to the user in the form, and transform this intermediary model into the complete one before inserting it into my database ?
That is, replace my action by something like that :
def register = Action {
implicit request =>
case class UserRegister(
username: String,
password: String,
email: String)
val userForm = Form(
mapping(
"username" -> nonEmptyText(8),
"password" -> nonEmptyText(8),
"email" -> email)(UserRegister.apply)(UserRegister.unapply)
val processedForm = userForm.bindFromRequest
processedForm.fold(hasErrors => BadRequest("Invalid submission"), success => {
val user = User(nextID, success.username, success.password, success.email, new Date())
// Register the user...
Ok("Account created")
}
Or is there another, cleaner way to do what I want ?
I've been through many tutorials and the book "Play for Scala", but in the only examples that I found, the models were fully filled by the forms... I really like Play! so far, but it looks like the documentation often lacks examples...
Thank you very much for your answers !
You have a few choices:
Firstly, you could make the id and created fields Option[Long] and Option[Date] respectively. Then use a mapping like:
val userForm = Form(
mapping(
"id" -> optional(longNumber),
"username" -> nonEmptyText(8),
"password" -> nonEmptyText(5),
"email" -> email,
"created" -> optional(date)
)(User.apply)(User.unapply)
)
That would, I think, be logical, since a User with a None id would indicate that it has not yet been saved. This works well when you want to use the same form mapping to update an existing record.
Alternately, you can use ignored mappings with some arbitrary placeholder data:
val userForm = Form(
mapping(
"id" -> ignored(-1L),
"username" -> nonEmptyText(8),
"password" -> nonEmptyText(5),
"email" -> email,
"created" -> ignored(new Date)
)(User.apply)(User.unapply)
)
This is not so good when reusing the form for update operations!
Finally, don't forget that your form mappings are bound/filled by functions that turn a tuple into an object, and an object into a tuple respectively. It's just a convenient convention to use the case class User.apply and User.unapply methods since these do just that. You could write alternative factory methods on your User object to handle form instantiation:
object User {
def formApply(username: String, password: String, email: String): User =
new User(-1L, username, password, email, new Date)
def formUnapply(user: User): Option[(String,String,String)] =
Some((user.username, user.password, user.email))
}
And then user those in the Form object:
val userForm = Form(
mapping(
"username" -> nonEmptyText(8),
"password" -> nonEmptyText(5),
"email" -> email
)(User.formApply)(User.formUnapply)
)
Also, it's worth noting that the Scala forms documentation is about to get much better in 2.2.1 (and in fact it might already have rolled out here).