Play Framework:Error type mismatch; found :Int required: play.api.mvc.Result - scala

I am trying to save form values to a database, and play I am getting the error:
type mismatch; found :Int required: play.api.mvc.Result
And here is my code :
Application.scala
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import views.html.defaultpages.badRequest
import play.api.data.validation.Constraints._
import models.User
import models.UserData
object Application extends Controller {
val RegisterForm = Form(
mapping(
"fname" -> nonEmptyText(1, 20),
"lname" -> nonEmptyText(1, 20),
"email" -> email,
"userName" -> nonEmptyText(1, 20),
"password" -> nonEmptyText(1, 20),
"age" -> number,
"choice" -> text,
"gender" -> text
)(User.apply)(User.unapply)
.verifying("Ag should be greater then or equal to 18", model => model.age match {
case (age) => age >= 18
})
)
def index = Action {
Ok(views.html.index(RegisterForm))
}
def register = Action { implicit request =>
RegisterForm.bindFromRequest().fold(
hasErrors => BadRequest(views.html.index(hasErrors)),
success => {
User.save(success)
}
)
}
}
User.scala
import anorm._
import play.api.db.DB
import anorm.SqlParser._
import play.api.Play.current
case class User (
fname: String,
lname: String,
email: String,
userName: String,
password: String,
age: Int,
choice: String,
gender: String
)
object User {
val userinfo = {
get[String]("fname") ~
get[String]("lname") ~
get[String]("email") ~
get[String]("userName") ~
get[String]("password") ~
get[Int]("age") ~
get[String]("choice") ~
get[String]("gender") map {
case fname~lname~email~userName~password~age~choice~gender =>
User(fname, lname, email, userName, password, age, choice, gender)
}
}
def save(ud: User) = {
DB.withConnection { implicit c =>
SQL ("insert into userinfo(fname,lname,email,userName,password,age,choice,gender) values ({fname},{lname},{email},{userName},{password},{age},{choice},{gender})")
.on('fname -> ud.fname, 'lname ->ud.lname ,'email ->ud.email, 'userName->ud.userName , 'password->ud.password ,'age->ud.age, 'choice->ud.choice,'gender->ud.gender)
.executeUpdate()
}
}
}
i took help from the scala cook book for this save functions but i am having problem as i am new in play scala maybe the mistake was minor one so please help me,all i want is to store all the input values in DB which was entered in the form

The problem is with your controller function register:
def register = Action { implicit request =>
RegisterForm.bindFromRequest().fold(
hasErrors => BadRequest(views.html.index(hasErrors)),
success => {
// You need to return a `Result` here..
// Maybe redirect to login?
// Redirect("/login")
User.save(success)
}
)
}
The problem is that User.save returns an Int, and the controller function is expecting a Result, like Ok(..), Redirect(...), etc. You need to do something with the result of User.save to return a Result.
It would be better if you used executeInsert() instead of executeUpdate(), as executeInsert returns Option[Long] by default--which will help you determine if the save was successful.
e.g.:
def save(ud: User): Option[Long] = {
DB.withConnection {implicit c =>
SQL("insert into userinfo(fname,lname,email,userName,password,age,choice,gender) values ({fname},{lname},{email},{userName},{password},{age},{choice},{gender})")
.on('fname -> ud.fname, 'lname ->ud.lname ,'email ->ud.email, 'userName->ud.userName , 'password->ud.password ,'age->ud.age, 'choice->ud.choice,'gender->ud.gender)
.executeInsert()
}
}
Then within your controller function use it like this:
def register = Action { implicit request =>
RegisterForm.bindFromRequest().fold(
hasErrors => BadRequest(views.html.index(hasErrors)),
success => {
User.save(success) map { newId =>
Redirect("/login") // or whatever you want this to do on success
} getOrElse {
InternalServerError("Something has gone terribly wrong...")
}
}
)
}
You can replace my placeholder results with something a little more meaningful in your application.

The save(ud:User) method returns the integer value. Action should always return Result, so write
success => {
val result = User.save(success)
Ok(result.toString)
}

Related

how to apply Form validators on object

I have an API in Scala. When I want to create a new User, i need validators on some fields (UserName, FirstName, LastName). I can't find a solution to apply the Form on my case class User. I thought using (User.apply) this will override automatically my User class, but this isn't happening.
User.scala
case class User(
id: Int = 0,
userName: String,
firstName: String,
lastName: String
)
object User {
import play.api.libs.json._
implicit val jsonWrites = Json.writes[User]
implicit val userReads = Json.reads[User]
def tupled = (User.apply _).tupled
}
// Form validator for post requests
object UserForm {
val form: Form[User] = Form(
mapping(
"id" -> number,
"userName" -> text(minLength = 5),
"firstName" -> text(minLength = 5),
"lastName" -> nonEmptyText
)(User.apply)(User.unapply)
)
}
UsersController.scala
def create = Action(parse.json) { implicit request => {
val userFromJson = Json.fromJson[User](request.body)
userFromJson match {
case JsSuccess(user: User, path: JsPath) => {
var createdUser = Await.result(usersRepository.create(user), Duration.Inf)
Ok(Json.toJson(createdUser))
}
case error # JsError(_) => {
println(error)
InternalServerError(Json.toJson("Can not create user"))
}
}
}
}
UsersRepository.scala
def create(user: User): Future[User] = {
val insertQuery = dbUsers returning dbUsers.map(_.id) into ((x, id) => x.copy(id = id))
val query = insertQuery += user
db.run(query)
}
(UsersRepository doesn't matter so much in this problem)
So, when I read the json, I think there need to apply the form validators
val userFromJson = Json.fromJson[User](request.body)
but nothing happening. Another problem is if I send from client a null parameter, will get an error, can not read and create an User.
For example :
"firstName": "" - empty userName will pass
"firstName": null - will fail
This depends on how is configured the User class in client (Angular), with the field null or empty in constructor. I prefer to set it null, even if is a string, if is not a required field (better NULL value in database, than an empty cell)
Try to use this:
request.body.validate[User]
One other thing, you shouldn't use
var createdUser = Await.result(usersRepository.create(user), Duration.Inf)
So use val´s over var´s and the other thing, you don't need to force the future to resolve, use it like this:
val createdUser = usersRepository.create(user)
createdUser.map(Ok(Json.toJson(_)))
And your action should be async.
Find a solution, my Form need to be part of object User, and not to be another object.
object User {
import play.api.libs.json._
implicit val jsonWrites = Json.writes[User]
implicit val userReads = Json.reads[User]
val form: Form[User] = Form(
mapping(
"id" -> number,
"userName" -> text(minLength = 2),
"firstName" -> text(minLength = 4),
"lastName" -> nonEmptyText
)(User.apply)(User.unapply)
)
def tupled = (User.apply _).tupled
}
and the method in Controller became :
def create = Action(parse.json) { implicit request => {
User.form.bindFromRequest.fold(
formWithErrors => BadRequest(Json.toJson("Some form fields are not validated.")),
success => {
val userFromJson = Json.fromJson[User](request.body)
userFromJson match {
case JsSuccess(user: User, path: JsPath) => {
val createdUser = Await.result(usersRepository.create(user), Duration.Inf)
Ok(Json.toJson(createdUser))
}
case error#JsError(_) => {
println(error)
InternalServerError(Json.toJson("Can not create user"))
}
}
}
)
}
}
I know, I need to format my code ... using IntelliJ is so annoying after Visual Studio :(

How to use scala case to have multiple parameters?

I've just discovered last week Scala language, with the Play 2 Framework, and I'm a little confused..
I try to make a simple form with an username and a password with this tutorial :
http://www.jamesward.com/2012/02/21/play-framework-2-with-scala-anorm-json-coffeescript-jquery-heroku
but in the controller I have a function who doesn't work :
def addUser() = Action { implicit request =>
userForm.bindFromRequest.fold(
errors => BadRequest,
{
case (username) =>
User.create(User(NotAssigned, username, password))
Redirect(routes.Application.index())
}
)
}
It returns : not found: value password
And if i put password in the case, it does'nt wook too..
Any idea ?
Application.scala :
package controllers
import play.api._
import play.api.mvc._
import play.api.data.Form
import play.api.data.Forms.{single, nonEmptyText}
import play.api.mvc.{Action, Controller}
import anorm.NotAssigned
import models.User
object Application extends Controller {
val userForm = Form {
tuple(
"username" -> nonEmptyText,
"password" -> nonEmptyText
)
}
def index = Action {
Ok(views.html.index(userForm))
}
def addUser() = Action { implicit request =>
userForm.bindFromRequest.fold(
errors => BadRequest,
{
case (username, password) =>
User.create(User(NotAssigned, username, password))
Redirect(routes.Application.index())
}
)
}
}
User.scala :
package models
import play.api.db._
import play.api.Play.current
import anorm._
import anorm.SqlParser._
case class User(id: Pk[Long], username: String, password: String)
object User {
val simple = {
get[Pk[Long]]("id") ~
get[String]("username") ~
get[String]("password") map {
case username~password => User(id, username)
case id~username => User(id, username)
}
}
def findAll(): Seq[User] = {
DB.withConnection { implicit connection =>
SQL("SELECT * FROM user").as(User.simple *)
}
}
def create(user: User): Unit = {
DB.withConnection { implicit connection =>
SQL("INSERT INTO user(username, password) VALUES ({username}, {password})").on(
'username -> user.username ,
'password -> user.password
).executeUpdate()
}
}
}
The form you're binding should contain all the values you want to extract, i.e:
import play.api.data.Form
import play.api.data.Forms.{tuple,nonEmptyText}
val userForm = Form(
tuple(
"username" -> nonEmptyText,
"password" -> nonEmptyText
)
)
def addUser() = Action { implicit request =>
userForm.bindFromRequest.fold(
errors => BadRequest,
{
case (username, password) => {
User.create(User(NotAssigned, username, password))
Redirect(routes.Application.index())
}
}
)
}
In James's example the form contains just a single field, which will extract to a single value (in your case, username.) Using the "tuple" form mapping will allow you to get more values out.
The second argument of fold() function is another function, which takes an object of Form class you're trying to bind to. In your case it would be an "userForm" object:
def addUser() = Action { implicit request =>
userForm.bindFromRequest.fold(
errors => BadRequest,
okForm => {
// whatever you want
}
)
}
We don't know the type of your form. So difficult to say more. But, as for me, using "case" here is not a good idea.

Scala Type Mismatch

I am having a problem with type mismatch.
type mismatch; found : Option[models.User] required: models.User
def authenticate = Action { implicit request =>
signinForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.signin(formWithErrors)),
user => Redirect(routes.Application.active).withSession(Security.username -> User.getUserName(user))
)
}
How can I force the function to accept Option[models.User] or can I convert the models.User into an Option?
The error occurs here: User.getUserName(user). getUserName requires models.User types.
===============================================
Update with all code used:
From User.scala
def authenticate(email: String, password: String) : Option[User] = {
(findByEmail(email)).filter { (user => BCrypt.checkpw(password, user.password)) }
}
def findByEmail(email: String) : Option[User] = {
UserDAO.findOne(MongoDBObject("email" -> email))
}
From Application.scala
val signinForm = Form {
mapping(
"email" -> nonEmptyText,
"password" -> text)(User.authenticate)(_.map(user => (user.email, "")))
.verifying("Invalid email or password", result => result.isDefined)
}
def authenticate = Action { implicit request =>
signinForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.signin(formWithErrors)),
user => Redirect(routes.Application.active).withSession(Security.username -> User.getUserName(user.get))
)
}
To de-option an Option[User] into a User, you can do one of the following:
1) The unsafe way. Only do this if you are sure that optUser is not None.
val optUser: Option[User] = ...
val user: User = optUser.get
2) The safe way
val optUser: Option[User] = ...
optUser match {
case Some(user) => // do something with user
case None => // do something to handle the absent user
}
3) The monadic safe way
val optUser: Option[User] = ...
optUser.map(user => doSomething(user))
The biggest thing is that, if it's possible that optUser might actually be None, you need to figure out what you actually want to happen in the case that there is no User object.
There's a lot more information about Option in other StackOverflow questions if you'd like to read more.

Play! Form that selects an item from a separate mongo collection

So for a system I am developing I am trying to do something similar to this:
If I have a Model called User, that has an _id (ObjectId), username, password, and then I am trying to create a new appointment, my form would look for a patient (display the patient name in the dropdown but really would pick up the patient's ObjectId), and appointment time.
Now I've looked everywhere and can't find anything remotely close to the solution i'm trying to attain.
In Application.scala, I have:
val appointmentForm= Form(
tuple(
"patient" -> nonEmptyText, // ObjectId
"startTime" -> nonEmptyText))
I am not sure how to quite work my view in order to reflect the patient. I know you have to do something like this:
#select(appointmentForm("patient"), options(..)
Can anyone give me any ideas as to how I can look up the patients for this example to pick up a Mongo ObjectId.
The ORM I am using btw is https://github.com/leon/play-salat
here is an example how I would do it:
routes:
GET /test controllers.Test.show
POST /test controllers.Test.submit
view:
#(f: Form[(ObjectId, String)], users: Seq[(ObjectId, String)])
#import helper._
#form(action = routes.Test.submit) {
#select(f("patient"), options = users.map(user => (user._1.toString, user._2)))
#inputText(f("startTime"))
<input type="submit" value="Submit!">
}
controller:
package controllers
import org.bson.types.ObjectId
import play.api.data.format.Formatter
import play.api.mvc._
import play.api.data.Forms._
import play.api.data._
import play.api.data.FormError
import play.api.Logger
object Test extends Controller {
/**
* Converts an ObjectId to a String and vice versa
*/
implicit object ObjectIdFormatter extends Formatter[ObjectId] {
def bind(key: String, data: Map[String, String]) = {
val error = FormError(key, "error.required.ObjectId", Nil)
val s = Seq(error)
val k = data.get(key)
k.toRight(s).right.flatMap {
case str: String if (str.length() > 0) => Right(new ObjectId(str))
case _ => Left(s)
}
}
def unbind(key: String, value: ObjectId) = Map(key -> value.toStringMongod())
val objectId: Mapping[ObjectId] = of[ObjectId]
}
// import to get objectId into scope
import ObjectIdFormatter._
// define user tuples consisting of username and ObjectId for the dropdown. In real lif the list is probably fetched from the db
def users: Seq[(ObjectId, String)] =
Seq((new ObjectId("4f456bf744aed129d04db1bd"), "dieter"), (new ObjectId("4faa410b44aec5a0a980599f"), "eva"))
val appointmentForm= Form(
tuple(
"patient" -> objectId, // use the ObjectIdFormatter
"startTime" -> nonEmptyText))
def show = Action {
Ok(views.html.test(appointmentForm, users))
}
def submit = Action { implicit request =>
appointmentForm.bindFromRequest.fold(
formWithErrors => {
Logger.warn("errors: " + formWithErrors.errors)
BadRequest(views.html.test(formWithErrors, users))
},
formContent => {
Logger.info("formContent: " + formContent)
Ok(views.html.test(appointmentForm, users))
})
}
}
Fyi, I was able to finally solve the problem after seeing this wonderful comment by maxmc. It turns out my problem was really a fundamental scala issue. I did not realize that List is an implementation of Seq. so using Mongo, in this example, what you have to do is in your code is the following:
CONTROLLER
def newAppointment= Action {
val pList = Patient.findAll.toList
Ok(views.html.admin.newuser(appointmentForm, pList))
}
View:
#(appointmentForm: Form[(String, String, String)], pList : List[Patient])
...
...
...
#select(
appointmentForm("patient"),
pList.map{ p =>
p.id.toString -> (p.patientName)
},
'_default -> "--- Select a Patient ---",
'_label -> "Patient"
)
the Model.findAll function returns Iterator[Type]. We don't want that. We need to retrieve a list that we can traverse inside the view. That's why you do findAll.toList . From there, the #select will map the pList and for each entry from the database have the id be associated to the patient name. Note that it is a string, because the Seq for the #Select tag requires Seq(String, String)

Scala + Play -> Type mismatch; found : anorm.RowParser Required: anorm.ResultSetParser[Option[models.User]]

SOLUTION: I could not figure our how to return the non-exists for of Option[User] so in the case of not user found I create a dummy user object and reason on it from the controller (feels awful but working...):
from Application.scala
val loginForm = Form(
tuple(
"email" -> text,
"password" -> text
) verifying ("Invalid email or password", result => result match {
case (email, password) => (User.authenticate(email, password).map{_.id}.getOrElse(0) != 0)
})
)
AS OPPOSED TO:
val loginForm = Form(
tuple(
"email" -> text,
"password" -> text
) verifying ("Invalid email or password", result => result match {
case (email, password) => User.authenticate(email, password).isDefined
})
)
++++++++++++++++++ ORIGINAL 2 ++++++++++++++++++
Thanks for the advice! I have made some change and seem to be getting closer however I can't figure out how to return an undefinded Option[user]. I have also tried case _ => null, See below:
From User.scala
case class User(id: Int, email: String, name: String, password: String)
object User {
// -- Parsers
/**
* Parse a User from a ResultSet
*/
val userParser = {
get[Option[Int]]("uid")~
get[Option[String]]("email")~
get[Option[String]]("fname")~
get[Option[String]]("pbkval") map {
case (uid~email~name~pbkval) => validate(uid,email, name, pbkval)
}
}
/**
* Retrieve a User from email.
*/
def findByEmail(email: String): Option[User] = {
DB.withConnection { implicit connection =>
SQL("select * from get_pbkval({email})").on(
'email -> email
).as(userParser.singleOpt)
}
}
/**
* Authenticated user session start.
*/
def authenticate(email: String, password: String): Option[User] = {
DB.withConnection { implicit connection =>
SQL(
"""
select * from get_pbkval({email})
"""
).on(
'email -> email
).as(userParser.singleOpt)
}
}
/**
* Validate entry and create user object.
*/
def validate(uid: Option[Int], email: Option[String], fname: Option[String], pbkval: Option[String]): User = {
val uidInt : Int = uid.getOrElse(0)
val emailString: String = email.getOrElse(null)
val fnameString: String = fname.getOrElse(null)
val pbkvalString: String = pbkval.getOrElse(null)
User(uidInt, emailString, fnameString, pbkvalString)
}
I guess it is clear that I am not really getting something fundamental here.. I have read through http://www.playframework.org/modules/scala-0.9.1/anorm and searched around for hours.. any help would be much appreciated!
You didn't specify which rows to map. After your row mapper, put a * to signify which rows to map. While you're at it, I find it easier to define my row mapper in a separate val. Something like this.
val user = {
get[Option[Int]]("uid")~
get[Option[String]]("email")~
get[Option[String]]("fname")~
get[Option[String]]("pbkval") map {
case uid~email~name~password => validate(uid,email, name, password)
}
}
def authenticate(email: String, password: String): Option[User] = {
DB.withConnection { implicit connection =>
SQL(
"""
select * from get_pbkval({email})
"""
).on(
'email -> email
).as(user *)
}
}
def validate(uid: Option[Int], email: Option[String], fname: Option[String], pbkval: Option[String]): Option[User] = {
if (uid != None) {
val uidInt : Int = uid.getOrElse(0)
val emailString: String = email.getOrElse(null)
val fnameString: String = fname.getOrElse(null)
val pbkvalString: String = pbkval.getOrElse(null)
User(uidInt, emailString, fnameString, pbkvalString)
} else { return null}
}
Note the "as" method now has two arguments, your row mapper (which is now defined as a val "user", and a "*" signifying that you want to map all of the rows.