1

私はこれらのケースクラスを持っています

case class Blog(id:Long, author:User, other stuff...)
case class Comment(id:Long, blog:Blog, comment:String)

データを送信するクライアント側のフォーム

blog_id:"5"
comment:"wasssup"

ユーザーがブログにコメントを追加できるようにする簡単なコードを書いています。
ユーザーはログインしているので、user_idクライアント側からは必要ありません。彼が誰であるかはわかっています...

blog_idデータベースからロードされたオブジェクトにバインドしたいと思いBlogます。存在しない場合はエラーを表示します。
Play フレームワーク ドキュメントの例は役に立ちません。
単一のオブジェクトとそのすべてのフィールドを表すフォームのマッピングのみを示します。
ここでは a のタプルを表し、 のタプルのみを提供してい(b:Blog, comment:String)ます。 Blogid

変換+検証+エラーメッセージを提供するマッピングが必要なので、次のように書くことができます:

val form = Form(
    tuple(
      "blog_id" -> blogMapping,
      "comment" -> nonEmptyText
    )
  )
  form.bindFromRequest().fold(...
  formWithErrors => {...
  }, {
    case (blog, comment) => {do some db stuff to create the comment}
  ...

「blogMapping」は他のマッピングと同様に機能し、投稿されたデータをオブジェクト (この場合は db からロードされたブログ) にバインドします。失敗した場合は、formWithErrors =>句で使用できるエラーを提供します。

これを達成する方法がわかりません。ドキュメントはここに少し欠けています...
どんな助けも大歓迎です!

4

3 に答える 3

2

私には、これは拘束力のある問題のようには見えません。

問題は、Model-View-Controller の分割に関するものです。バインディングはコントローラー アクティビティであり、Web データ (ビューから) をデータ モデル (モデルで使用するため) にバインドすることです。一方、データのクエリは、モデルによって処理されます。

したがって、これを行う標準的な方法は次のようになります。

// Defined in the model somewhere
def lookupBlog(id: Long): Option[Blog] = ???

// Defined in your controllers
val boundForm = form.bindFromRequest()
val blogOption = boundForm.value.flatMap {
  case (id, comment) => lookupBlog(id)
}

blogOption match {
  case Some(blog) => ??? // If the blog is found
  case None => ??? // If the blog is not found
}

ただし、バインディングでデータベース ルックアップを処理することに決めた場合 (長期的にはスパゲッティ コードにつながるため、これには強くお勧めしません)、次のようなことを試してください。

class BlogMapping(val key: String = "") extends Mapping[Blog] {
  val constraints = Nil
  val mappings = Seq(this)

  def bind(data: Map[String, String]) = {
    val blogOpt = for {blog <- data.get(key)
                       blog_id = blog.toLong
                       blog <- lookupBlog(blog_id)} yield blog
    blogOpt match {
      case Some(blog) => Right(blog)
      case None => Left(Seq(FormError(key, "Blog not found")))
    }
  }

  def unbind(blog: Blog) = (Map(key -> blog.id.toString), Nil)

  def withPrefix(prefix: String) = {
    new BlogMapping(prefix + key)
  }

  def verifying(constraints: Constraint[Blog]*) = {
    WrappedMapping[Blog, Blog](this, x => x, x => x, constraints)
  }

}

val blogMapping = new BlogMapping()
val newform = Form(
  tuple(
    "blog_id" -> blogMapping,
    "comment" -> nonEmptyText
  )
)

// Example usage
val newBoundForm = newform.bindFromRequest()
val newBoundBlog = newBoundForm.get

私たちが行った主なことは、カスタム Mapping サブクラスを作成することです。これは状況によっては良い考えかもしれませんが、それでも最初のアプローチをお勧めします。

于 2013-04-09T16:44:41.000 に答える
1

フォーム定義ですべて実行できます。

あなたの例からいくつかの単純なスカラ クラスとオブジェクトを作成しました。

models/Blog.scala

package models

/**
 * @author maba, 2013-04-10
 */
case class User(id:Long)
case class Blog(id:Long, author:User)
case class Comment(id:Long, blog:Blog, comment:String)

object Blog {
  def findById(id: Long): Option[Blog] = {
    Some(Blog(id, User(1L)))
  }
}

object Comment {

  def create(comment: Comment) {
    // Save to DB
  }
}

controllers/Comments.scala

package controllers

import play.api.mvc.{Action, Controller}
import play.api.data.Form
import play.api.data.Forms._
import models.{Comment, Blog}

/**
 * @author maba, 2013-04-10
 */
object Comments extends Controller {

  val form = Form(
    mapping(
      "comment" -> nonEmptyText,
      "blog" -> mapping(
        "id" -> longNumber
      )(
        (blogId) => {
          Blog.findById(blogId)
        }
      )(
        (blog: Option[Blog]) => Option(blog.get.id)
      ).verifying("The blog does not exist.", blog => blog.isDefined)
    )(
      (comment, blog) => {
        // blog.get is always possible since it has already been validated
        Comment(1L, blog.get, comment)
      }
    )(
      (comment: Comment) => Option(comment.comment, Some(comment.blog))
    )
  )

  def index = Action { implicit request =>
    form.bindFromRequest.fold(
      formWithErrors => BadRequest,
      comment => {
        Comment.create(comment)
        Ok
      }
    )
  }
}
于 2013-04-10T14:09:00.867 に答える