Play! 2.1のroutesでOption型のパラメータを・・・
やりたいこと
あー、タイトル分かりにくくてすみません。
今作ってるサイトで、要はこういうことをやりたいんです。
GET /$areaId<[0-9]+> controllers.Foo.bar(areaId: Int, subAreaId: Option[Int] = None) GET /$areaId<[0-9]+>/$subAreaId<[0-9]+> controllers.Foo.bar(areaId: Int, subAreaId: Option[Int])
でも、エラーが出る。
No URL path binder found for type Option[Int]. Try to implement an implicit PathBindable for this type.
ググったらStackOverflowに同じ質問があった。
Play 2.0にはあった機能が2.1で無くなったらしい。言われてみると、2.0時代に使った記憶もあるし・・・バージョンアップして機能が削られるって珍しいね。
解決方法
SOの通りなんだけど、補足。
以下の様なファイルを作る。
package com.example.play import play.api.mvc.PathBindable object Binders { implicit def OptionBindable[T : PathBindable] = new PathBindable[Option[T]] { def bind(key: String, value: String): Either[String, Option[T]] = implicitly[PathBindable[T]]. bind(key, value). fold( left => Left(left), right => Right(Some(right)) ) def unbind(key: String, value: Option[T]): String = value map (_.toString) getOrElse "" } }
で、Build.scalaをちょこっと修正。以下、自分のプロジェクトのファイルから抜粋。
val website = play.Project( appName + "-website", appVersion, appDependenciesWebsite ).settings( // Add your own project settings here lessEntryPoints <<= baseDirectory(customLessEntryPoints), resolvers ++= Seq( Resolver.url("play-plugin-releases", new URL("http://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/"))(Resolver.ivyStylePatterns) ), routesImport += "com.example.play.Binders._" // ← この行を追加!! ).dependsOn(common, common % "test->test")
まとめ
Play 2.1のroutesでOptionを取れるようにする方法を簡単に説明した。2.0では問題なかったが、2.1で問題が出たので、それの回避方法。
Play開発チームは勝手に機能を削るのはやめて欲しい。そこそこ使えそうな機能なのに・・・