Routes with optional parameter - Play 2.1 Scala

自古美人都是妖i 提交于 2019-11-27 03:22:37

问题


So in Play 2.0 I had this:

GET     /tasks/add              controllers.Tasks.addTask(parentId: Option[Long] = None)
GET     /tasks/:parentId/add    controllers.Tasks.addTask(parentId: Option[Long])

With a controller method like this:

def addTask(parentId: Option[Long]) = Action { 
    Ok(views.html.addTask(taskForm, parentId))  
}

And it was working. As I migrated to 2.1, it seems to complain about these lines with: No URL path binder found for type Option[Long]. Try to implement an implicit PathBindable for this type. Basically, what I am trying to accomplish is to have route tasks/add and route tasks/123/add link to the same method that accepts an Optional[Long]. Any idea how to do this? Thanks.

Ok, so I got a kind of it's not a bug, it's a feature response on Lighthouse: "We removed Option[Long] support in path bindables since it doesn't make sense to have a optional path parameter. You can implement your own path bindable that supports it if you please." So far I have 2 solutions, passing -1 as parentId, which I do not really like. Or having 2 different methods, which probably makes more sense in this case. Implementing the PathBindable doesn't seem too feasible right now, so I will probably stick with having 2 methods.


回答1:


Play 2.0 supported Option in path parameters, Play 2.1 no longer supports this, they removed the PathBindable for Option.

One possible solution would be:

package extensions
import play.api.mvc._
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 ""
  }
}

And add this to Build.scala using routesImport += "extensions.Binders._". Run play clean ~run and it should work. Reloading the Binders on the fly only sometimes works.




回答2:


I think you have to add a question mark:

controllers.Tasks.addTask(parentId: Option[Long] ?= None)




回答3:


From this routes-with-optional-parameter the suggestion goes like:

GET   /                     controllers.Application.show(page = "home")
GET   /:page                controllers.Application.show(page)



回答4:


The simple solution to your problem, without having to pass a default value, is to add a simple proxy method that wraps the parameter in an option.

Routes:

GET     /tasks/add              controllers.Tasks.addTask()
GET     /tasks/:parentId/add    controllers.Tasks.addTaskProxy(parentId: Long)

Controller:

def addTask(parentId: Option[Long] = None) = Action { 
    Ok(views.html.addTask(taskForm, parentId))  
}

def addTaskProxy(parentId: Long) = addTask(Some(parentId))



回答5:


I had the same thing and more if you specify the pass as GET/foo:id and controllers.Application.foo(id : Option[Long] ?= None) you get an error It is not allowed to specify a fixed or default value for parameter: 'id' extracted from the path on the other side you can do as follows GET/foo controllers.Application.foo(id : Option[Long] ?= None) and it will work expecting that your request looks like as .../foo?id=1



来源:https://stackoverflow.com/questions/14980952/routes-with-optional-parameter-play-2-1-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!