前回の記事で、「あれ? Double(Float)型使えないの? 少数とかどうするの?」と思った方もいると思います。そうでないにしても、他の型にマッピングしたいというのは当然の要望でしょう。
そこで今回は、任意の型にフォームデータをマッピングする方法を紹介します。
まず必要なのは play.api.data.format.Formatter トレイトの実装クラスです。これを提供するメソッドを作成します。作成する場所は object であればどこでもかまいませんが、どうせ controllers でしか使用しないというのであれば、controllers のパッケージオブジェクトだと何かと楽です(controllers のパッケージオブジェクトでは上手くいかないようでした)。なぜ object かというと、以下のように implicit def なので import が必要だからです。
まず、作成するメソッドに必要なクラス等を使用する import 宣言は以下のとおりです。
import play.api.data._ import Forms._ import play.api.data.format._ import Formats._
そして作成するメソッドですが、以下は Double 型へマッピングする場合の例です。
/**
* リクエストデータを Double 型に変換するフォーマッタを取得します。
*/
implicit def doubleFormat = new Formatter[Double] {
/**
* このフォーマットについて画面に表示する際に使用するメッセージ
*/
override val format: Option[(String, Seq[Any])] = Some("format.double", Nil)
/**
* リクエストデータを Double 型に変換します。
*
* @param key リクエストデータを取り出す際に使用するキー値
* @param data リクエストデータ
* @return Double 型への変換が失敗した場合フォームエラー。成功した場合変換した値
*/
def bind(key: String, data: Map[String, String]): Either[Seq[FormError], Double] = {
stringFormat.bind(key, data).right.flatMap { s =>
scala.util.control.Exception.allCatch[Double]
.either(s.toDouble) // 文字列から Double に変換する処理
.left.map(e => Seq(FormError(key, "error.double", Nil))) // それが失敗した場合
}
}
/**
* Double 型の値から、リクエストデータ用の文字列に変換します。
*/
def unbind(key: String, value: Double): Map[String, String] = Map(key -> value.toString)
}
ここまでやればもう使い物になるのですが、もう一声、上記のメソッドの直下あたりで以下のようにやっておくとより格好がつきます。
val double = of[Double]
このようにフォームデータマッピングで使用できます。
val helthForm = Form(
tuple(
"tall" -> double,
"weight" -> optional(double)))