endless pulse

どっくんどっくんふるえる毎日を過ごしています

Play framework 2.3 for Scala で、フォームを使ってみる

Play framework 2.3 for Scalaで、フォームからDBへ保存するところをつくってみました。そのおぼえがき。
View…フォームの見え方
Controller…フォームの定義、フォーム表示・受け取り(+DBへの橋渡し)
って感じかな。Controllerがモリモリになってしまいそうだけど、まずは簡単に。

Controller:フォームの定義

先にControllerから。フォームを定義します。

import play.api.data._
import play.api.data.Forms._

case class Book (title : String, price : Int) // ケースクラスを定義する

object XXX {
  val bookForm = Form( // フォームの「型」定義
    "title" -> text,
    "price" -> number(min = 0, max = 1000000)
  ) (Book.apply) (Book.unapply)
}

ケースクラスとフォームの型が別々のファイルにあっても大丈夫。DBアクセスのため、Model側で定義したケースクラスでも問題なし。ネストしたケースクラスでもいけるよう。

View側のフォームから送られてくる値の「制約」を、Form( 〜 )の中に書きます。今はtextscala.String)と、number (scala.Int)しか定義してませんが、いろいろ制約は書けるみたい。リストも送れる! 以下の公式ドキュメントの"Defining constraints on the form"のあたり参照。
Scala Forms - 2.3.x

Form( 〜 )のあとのケースクラスのapply、unapplyでケースクラスに変換しているけれど、これをTuppleやMapに変換しても使える。便利。


参考サイト
【#Play】Play Framework 2.3 (Scala) を使った Web システム開発入門 #Play_ja #Scala #rpscala - Qiita

Controller:フォームの表示・受け取り(+DBへの橋渡し)

先に定義したフォームの表示・受け取りをするアクションを定義します。

import play.api.mvc._

import play.api.data._
import play.api.data.Forms._

// 
// 上で定義したケースクラス case class Book...(importでも可)

object XXXController extends Controller {

  // 
  // 上で定義したフォーム val bookForm...(を使えるようにしておく)


  // 表示用
  def showBookForm = Action { implicit request =>
    Ok(views.html.register(bookForm))
  }

 // 登録用
  def register = Action { implicit request =>
    bookForm.bindFromRequest.fold (
      errors => BadRequest(views.html.error("フォームの入力エラー時の表示")),
      book => {
        // 成功時の処理をここに書く、以下は例
        Ok(views.html.result(book.title, book.price)
      }
    )
  }
}

処理の中に、ModelのDAOとかを使いたい場合は、ActionではなくてDBActionにする。DBActionは、play.api.db.slick._にあるので、importする必要がある。
DBとのつなぎは以下のサイトが詳しかったので、そちら参照。
【#Play】Play Framework 2.3 (Scala) を使った Web システム開発入門 #Play_ja #Scala #rpscala - Qiita

routesに定義

conf/routes ファイルに、アクセスしたいControllerの定義をかいておく。

# Login
GET		/register			controllers.XXXController.showBookForm()
POST	/register			controllers.XXXController.register()
View:フォームの見え方

表示用のテンプレートを定義。
Controllerで指定したviews.html.xxxというのは、package viewsの中の、xxx.scala.htmlに該当する。
公式ドキュメント:Scala Templates - 2.3.xScala Forms - 2.3.xShowing forms in a view templateの項あたり

views/register.scala.html

@(bookForm: Form[controllers.Book])

@import helper._

<!-- HTMLヘッダー、レイアウトを普通に書ける -->

<div>
          @form(controllers.routes.XXXController.register()) {
            <fieldset>
              @inputText(bookForm("title"),		 '_label -> "タイトル",		'size -> 40)
              @inputText(bookForm("price"),         	'_label -> "値段", 			'size -> 40)
            </fieldset>
            <div class="actions">
              <input type="submit">
            </div>
          }
</div>

公式ドキュメントScala Forms - 2.3.xにもある通り、@inputTextの部分はinputフィールドのtypeに合わせて様々に用意されている。

views/result.scala.html

@(title: String, price: String)

<!-- HTMLヘッダー、レイアウトを普通に書ける -->

<table>
  <tr>
    <th>タイトル</th>
    <th>値段</th>
    <td>@title</td>
    <td>@price</td>
  </tr>
</table>

公式ドキュメントScala Templates - 2.3.xの通り、Listを受け取ってループで回したりなど、直感的に書ける。便利。


これで、一応使ってみれるフォームはできる。
Viewがかなり書きやすい印象はある。


参考サイト