概要
ScalaのPlay Frameworkで手始めにForm処理を一つ作ってみようとしたら、ネットにあるサンプルソースから仕様が意外に変わっていたので、2.6時点での作成方法を情報整理をしてみました。
前提
ログイン画面をイメージしてFormの処理を作ってみました。気づいた点やはまった点を、ソースを交えて記載しています。
サンプルソース
【routesファイル】
GET     /      controllers.LoginController.loginInit
GET     /login controllers.LoginController.loginInit
POST    /login controllers.LoginController.loginSubmit
# Map static resources from the /public folder to the /assets URL path
GET     /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
【models】
package models
case class LoginUser(
    userid:String, 
    userpw:String); 
【controllers】
package controllers
import javax.inject._
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import models._
import play.api.data.validation.Valid
import play.api.data.validation.Constraint
import play.api.data.validation.Invalid
import play.api.i18n.I18nSupport
@Singleton
class LoginController @Inject()(cc: ControllerComponents) extends AbstractController(cc) with I18nSupport {
  // ログインフォーム
  // 空白チェックにオリジナルメッセージを設定してみる
  val loginUserForm = Form( mapping("userid" -> text.verifying("ユーザIDを入力してください" , {!_.isEmpty()}) , 
                                    "userpw" -> text.verifying("パスワードを入力してください" , {!_.isEmpty()})
                                    )
                                    (LoginUser.apply)(LoginUser.unapply) 
                           )
  
  // ログイン画面の初期表示
  def loginInit() = Action { implicit request =>
     Ok( views.html.login(loginUserForm) )
  }
  
  // ログイン画面のSubmit
  def loginSubmit() = Action { implicit request: Request[AnyContent] =>
     loginUserForm.bindFromRequest.fold(
         // 入力チェックNG
         errors => {           
           BadRequest( views.html.login(errors) )
         },
         // 入力チェックOK
         success => {
           val loginUser = loginUserForm.bindFromRequest.get
           Ok( views.html.loginSuccess() )
         }        
     )
  }
}
Controllerの作成にあたってまず留意すべきことは、こちらのstackoverflowの記事より、2.6からクラスの継承に必要なものが変わった点です。
あと、これは別に2.6だからということではないのですが、空白チェックにあえてverifyingを使って試しにオリジナルのメッセージを設定してみました。また、入力チェックの詳細についてはPlayframework 2.0(Scala)でサンプルアプリケーション作成-3.メッセージの国際化(i18n)対応が参考になります。
【view】
@(loginUserForm : Form[LoginUser])(implicit request: RequestHeader, messagesProvider: MessagesProvider)
@import helper._
@main("サンプル"){
    <font size=5>■ログイン画面</font><br/>
    @helper.form( action = helper.CSRF(routes.LoginController.loginSubmit) ){
        <fieldset>
          @helper.inputText(loginUserForm("userid") , '_label -> "ログインID")
          @helper.inputPassword(loginUserForm("userpw") , '_label -> "パスワード")
        </fieldset>
        <input type="submit" value="ログイン">
    }
}
@import helper._
@main("サンプル"){
    <font size=5>■ログイン成功</font>
}
まず、冒頭のimplicit parameterです。こちらのstackoverflowの記事によると、これがないと2.6ではコンパイルエラーになるそうです。
また、2.6では初期設定ではCSRFの設定がONになっているので、こちらのstackoverflowの記事によると、actionでCSRFのメソッドを使う必要があるとのこと。
また、2.6というわけではないですが、フィールドコンストラクタがviewのヘルパーの引数に設定できるので、フォームテンプレートヘルパーの利用を参考に試しに設定してみました。