2

I'm having problem inserting (or updating) new data to database using anorm in Play Framework 2.0. My model is a blog post defined in the following code:

case class Post(title: String,
    content: String,
    created: String,
    lastUpdate: String,
    writer: Long,
    id: Long = 0)

Then I do this on the insert function:

def create(title: String, content: String, userId: Long) = {
  DB.withConnection { implicit connection =>
    SQL("INSERT INTO post (title, content, created, writer) VALUES ({title}, {content}, NOW(), {writer})")
        .on(
          'title -> title,
          'content -> content,
          'writer -> userId).executeUpdate()
}

And the form:

val postForm = Form(
  tuple(
    "title" -> nonEmptyText,
    "content" -> nonEmptyText))

I did not have a userId field in the form because I don't trust the user's input on their own id. I get it from session. Anyway, that's why I can't directly put the validation code in postForm's declaration (because I think I can't access session both from the form and from model). And here's when it becomes ugly. If the post is invalid, anorm throws an Exception so I need to pass the error to user AFTER the fold function like:

postForm.bindFromRequest.fold(
  formWithErrors => BadRequest(views.html.post.newPost(formWithErrors)),
    newPost => {
      try {
        val userId = request.session.get("id").getOrElse("0")
        models.Post.create(newPost._1, newPost._2, userId.toLong)
      } catch {
        case e => BadRequest(views.html.post.newPost(postForm.fill(newPost)))
      }
    Redirect(routes.Application.index)
})

First, the try-catch is ugly. Second, the BadRequest call don't work. What am I doing wrong? What is the best way to handle errors in insert / update? I have the same problem with a login form, but it's not as bad as this because I can actually handle errors at login form declaration.

Thanks before.

bertzzie
  • 3,558
  • 5
  • 30
  • 41

1 Answers1

1

Assuming the error is on an integrity constraint like 0 not existing in the database, what about something like this ?

    postForm.bindFromRequest.fold(   
        formWithErrors => BadRequest(views.html.post.newPost(formWithErrors)),
        newPost => {
            request.session.get("id").map({ userId=> 
               models.Post.create(newPost._1, newPost._2, userId.toLong)       
               Redirect(routes.Application.index) 
            }).getOrElse{
                BadRequest(views.html.post.newPost(postForm.fill(newPost))) 
            }
        }   
    )

You don't give invalid information to anorm and don't get an error ...

ps : I don't have a scala compiler on hand to check the syntax right now, I might have missed a paren or mixed a paren with a curly :)

Jean
  • 21,329
  • 5
  • 46
  • 64
  • This will solve the problem for the postForm, but I think it won't solve the other problem: double data on database. For example: user's email on registration. Thanks for answering anyway. – bertzzie Jul 11 '12 at 13:37
  • You could catch the database error in the model and have your User.create method return an Option or an Error and go from there – Jean Jul 11 '12 at 15:19
  • have you checked this ? http://stackoverflow.com/questions/6323961/how-should-i-use-mayerrintegrityconstraintviolation-int-in-scala-and-anorm – Jean Jul 11 '12 at 15:22