show.scala.htmlでは、<html>タグや<body>タグなどは一切記述していません。しかし、「http://localhost:9000/show」をWebブラウザで開いてソースを見ると、それらのタグが記述されています。これは、show.scala.htmlでmain.scala.htmlをincludeしているからです。
3行目に「@main」という記述があります。ここで、main.scala.htmlに対して文字列(タイトル)と{〜}で囲った内容を渡しており、main.scala.htmlでは、1つ目の引数をtitle、2つ目の引数とcontentにバインドしています。
@(title: String)(content: Html) <!DOCTYPE html> <html> <head> <title>@title</title> ・ ・ </head> <body> @content </body> </html>
<head>タグの中で@title、<body>タグの中で@contentとして、バインドされた内容を参照しています。こうすることで、main.scala.htmlに基本的なレイアウトを用意して<body>内だけを切り替えることができます。
テンプレートのincludeを利用すれば、再利用可能なタグを簡単に作成できます。
先ほど作成したshow.scala.htmlでは、List[String]データをリスト表示していました。この部分をタグとして別ファイルに切り出してみましょう。まずは、views/tagsディレクトリを作成し、iterateTag.scala.htmlを作成します。
@(list: List[String]) <ul> @for(item <- list) { <li><p>@item</p></li> } </ul>
このテンプレートを使用するように、show.scala.htmlファイルを修正します。上記テンプレートをimportし、iterateTagを使用しています。メソッドを定義し、別のメソッドから呼び出すかのように簡単にできることが分かります。
@(message:String,userList:List[String]) @import tags.iterateTag @main("show scala templates") { <h1>@message</h1> @iterateTag(userList) }
ここでは、Scala Templatesの基本的な使用方法を紹介しました。この章の内容は、こちらを基に作成しているので、併せてご覧ください。
Scala Templatesを使ったviewの記述方法が分かったので、次は、Formを使ってコントローラにデータの送信を行ってみましょう。gyroアプリで、ユーザー登録を模した機能を実装してみます。
Play 1.xのときは、Formデータはモデルオブジェクトに直接バインドされていましたが、Play 2.xではplay.api.data.Formを使用してFormデータをバインドします。
まずは、ユーザーを表すモデルを定義しましょう。modelsパッケージを作成し、そこに「models.scala」という名前でファイルを作成します。このファイルには、いろいろなモデルオブジェクトが定義されることを想定しています。
次のように内容を記述しましょう。
package models /** ユーザーモデル */ case class User(name: String, email: String, age: Int)
そして、ユーザーに関連する新しいコントローラ、UserControllerを定義しましょう。新しくcontrollers/UserCOntroller.scalファイルを作成します。
package controllers import play.api._ import play.api.mvc._ import play.api.data._ import play.api.data.Forms._ import models._ object UserController extends Controller { /** Form定義 */ val userForm = Form( mapping( "name" -> text, "email" -> text)(User.apply)(User.unapply)) /** 初期画面関数 */ def entryInit = Action { val filledForm = userForm.fill(User("user name", "email address")) Ok(views.html.user.entry(filledForm)) } /** ユーザー登録関数 */ def entrySubmit = Action { implicit request => val user = userForm.bindFromRequest.get println(user) Ok(views.html.user.entrySubmit()) } }
UserControllerでは、まずユーザー登録用Formを定義しています。今回、ポストするデータは、先ほど定義したUserモデルとマッピングしています。mapping関数でフィールド名と属性をマッピングするのですが、その後にUserオブジェクトを構築・分解するための関数を定義しています。
サンプルでは、Userオブジェクトはcaseクラスになっているので、デフォルトで用意されているapply/unapplyをそのまま渡せば問題ありません。
もし、Userオブジェクトが持つ必要のないフィールドをフォームが持つ場合、apply/unapplyを渡している個所で、自分で構築/分解用関数を定義します。
ちなみに、Play公式サイトにある「複雑なオブジェクトの構築」には、その例が出ていますので、確認してみてください。
entryInit関数は、ユーザー登録画面表示時に実行されます。Form.fill関数は、フォームに対して初期値を表示したい場合に使用します。entrySubmit関数は、次に作成するScala Templatesからポストされたデータをフォームから取得して表示しています。bindFromRequest関数を使用すれば、HTTPリクエストからそのままバインドできます。
なお、この関数ではHTTPリクエストがスコープ内になければいけないので、implicitでrequestを持つようにしています。
次に、ユーザー登録画面表示と登録データポストのためのroutesを定義します。
GET /user/entry controllers.UserController.entryInit POST /user/entry controllers.UserController.entrySubmit
最後にviews/userディレクトリを作成し、そこに2つファイルを作成しましょう。
1つ目は、入力用フォーム画面がある、entry.scala.htmlです。
@(userForm: Form[User]) @import helper._ @main("entry user") { <h1>Entry user</h1> @helper.form(action = routes.UserController.entrySubmit) { <fieldset> <legend>input user info.</legend> @helper.inputText(userForm("name")) @helper.inputText(userForm("email")) </fieldset> <input type="submit" value="entry"> } }
この画面では、引数としてコントローラで初期値が設定された状態のFormオブジェクトを受け取っています。
ここで使用している@helperとは、Scala Templates内でフォームやフィールドを生成するためのヘルパ関数です。ヘルパ関数を使用すれば、フォームのポスト先をリバースコントローラで指定できたり、フィールドに対して制約やエラー情報を付与した状態でHTMLを生成できます。
この画面ではヘルパ関数をそのまま使用していますが、<input>要素をカスタマイズすることも可能です。その方法については次回以降紹介する予定です。
なお、ヘルパ関数については、こちらに詳細情報がありますので、ご確認ください。
そして、登録完了画面、entrySubmit.scala.htmlを作成します。こちらは登録完了用メッセージを表示しているだけです。
@main("entry user submit") { <h1>Entry Success!</h1> }
ここまでできたら、Playコンソールでアプリを起動して動作を確認してみましょう。「http://localhost:9000/user/entry」にアクセスすると、登録画面が表示されます。値を入力してボタンをクリックすると、コンソールに入力したフォーム情報が表示されます。
Copyright © ITmedia, Inc. All Rights Reserved.