2013-02-20 12 views
14

Więc zagraj 2.0 miałem to:Trasy z opcjonalnym parametrem - Play 2.1 Scala

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

Dzięki metodzie kontrolera tak:

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

I to działa. Po migracji do wersji 2.1 wydaje się, że narzeka na te linie: No URL path binder found for type Option[Long]. Try to implement an implicit PathBindable for this type. Zasadniczo próbuję osiągnąć połączenie tasks/add i trasy tasks/123/add z tą samą metodą, która akceptuje numer Optional[Long]. Masz pomysł, jak to zrobić? Dzięki.

Ok, więc dostałem coś w rodzaju tego, że to nie jest błąd, to odpowiedź na temat funkcji w Lighthouse: "Usunęliśmy obsługę opcji [Long] w bindables ścieżki, ponieważ nie ma sensu mieć opcjonalnego parametru ścieżki. Potrafię zaimplementować twoją własną ścieżkę, która będzie ją wspierała, jeśli zechcesz. " Do tej pory mam 2 rozwiązania, przekazując -1 jako parentId, którego tak naprawdę nie lubię. Lub posiadające 2 różne metody, co prawdopodobnie ma więcej sensu w tym przypadku. Implementacja PathBindable nie wydaje się teraz zbyt wykonalna, więc zapewne pozostanę przy dwóch metodach.

Odpowiedz

13

Zagraj 2.0 obsługiwane Option w parametrach toru, Play 2.1 nie jest już popiera to, usunęli PathBindable for Option.

Możliwym rozwiązaniem byłoby:

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 "" 
    } 
} 

i dodać do Build.scala użyciu routesImport += "extensions.Binders._". Uruchom play clean ~run i powinno działać. Przeładowywanie binderów w locie tylko czasami działa.

+0

Dzięki, zgłosiłem to. Czy masz pojęcie, jak uzyskać pożądane zachowanie, bez czekania na poprawkę? – Laky

+2

Ok, więc: "Usunęliśmy wsparcie opcji [Long] w powiązaniach ścieżek, ponieważ nie ma sensu mieć opcjonalnego parametru ścieżki. Możesz zaimplementować własną ścieżkę, która będzie ją obsługiwać, jeśli będzie taka potrzeba." Ale przekazanie Opcji zamiast jakiejś arbitralnej wartości wydaje mi się dużo przyjemniejsze. Czy to nie dlatego mamy pierwsze opcje? Być może wolę stworzyć dwie różne metody w tym przypadku, ponieważ byłoby to bardziej sensowne niż przekazywanie -1 jako id. – Laky

+4

Tak, masz rację, to znacznie lepiej. Nie rozumiem jednak ich decyzji, dlaczego usunąć coś, co pozwalało na ładniejsze adresy URL? –

5

Chyba trzeba dodać znak zapytania:

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

+2

No to tylko dla parametrów kwerendy, a nie na części ścieżki. –

+0

@Marius robi dobry punkt, ale +1 w każdym razie, ponieważ odpowiedziałeś na pytanie w tytule: "Trasy z opcjonalnym parametrem" –

5

Od tego routes-with-optional-parameter propozycja idzie tak:

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

Wiem jednak o tym, ale chciałbym omijać konieczność przekazania wartości domyślnej. Parametr powinien zawierać identyfikator lub nic. Mógłbym przekazać -1 lub coś podobnego do wskazania nicości, ale wolałbym skorzystać z Opcji, ponieważ wydaje mi się o wiele ładniejsza. – Laky

+0

Co jeśli chcę obliczyć parametr domyślny w czasie wykonywania? Co powinienem używać jako literału dla parametru domyślnego? –

+0

Nie mogę uruchomić tej techniki. Otrzymuję http 500. Używam POST. POST/copy /: param1 /: param2 @ controllers.MyController.copy (param1, param2) POST/copy /: param2 @ controllers.MyController.copy (param1 = "", param2). Żądanie postu jest "/ copy/somestring" – Skychan

0

miałem to samo i więcej, jeśli podasz uchodzić GET/foo:id i controllers.Application.foo(id : Option[Long] ?= None) pojawi się błąd It is not allowed to specify a fixed or default value for parameter: 'id' extracted from the path z drugiej strony można to zrobić w następujący sposób GET/foo controllers.Application.foo(id : Option[Long] ?= None) i będzie działać spodziewa się, że prośba wygląda jak .../foo?id=1

2

Proste rozwiązanie problemu, bez konieczności przekazywania wartości domyślnej, polega na dodaniu prostej metody proxy, która opakowuje parametr w opcję.

Trasy:

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

kontrolera:

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

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

Obejście problemu, wciąż nieprzyjemne – Sorona

Powiązane problemy