2

В моем конкретном случае у меня есть меню, которое отображается на всех страницах. Содержимое меню загружается из базы данных с использованием пятна и неявно передается в представление. Все это выглядит следующим образом:Как обрабатывать неявно прошедшие фьючерсы в представлениях воспроизведения

Контроллер

class Application @Inject()(
    implicit val menuContext: MenuContext 
) extends Controller { 

    def index = Action.async { 
    val content: Future[Content] = getContent 
    content.map(c => Ok(views.html.index(c))) 
    } 
} 

MenuContext

class MenuContext { 
    val models: Future[List[SomeModel]] = getModelsFromDB 
} 

Посмотреть

@(content: Content)(implicit menuContext: MenuContext) 
... 
@menuContext.models // how to access my actual model and not the Future? 
... 

Как мне получить доступ к List[SomeModel] на мой взгляд? Есть ли эквивалент Action.async в игре для передачи неявных параметров? Или, может быть, даже лучшее решение для всего, что требуется (почти) для всех просмотров?

+1

исполнение Будущее, безусловно, задача бэк- конец, а не шаблон. Вы должны передать фактическую модель в представление. –

+0

Извините мой вопрос noobish, но как мне это сделать неблокирующимся способом? – Roman

ответ

3

OK Я добавляю еще один ответ здесь, чтобы конкретно попытаться сделать инъекцию меню в свои действия.

Основная проблема заключается в том, что вам нужно, чтобы ввести меню в только нужное время, а именно:

  • Если у вас есть готовые данные (или, по крайней мере, Future держа данные)
  • Когда вы знаете, какой шаблон будет оказан
  • Когда вы знаете, что код состояния вы будете возвращаться

Бека из-за этих ограничений мы не можем использовать ActionBuilder или ActionRefiner - они предполагают, что ваш внутренний блок кода контроллера выдаст готовый Result.

Так вместо этого, мы определим черту, мы можем смешивать в контроллерах:

trait MenuDecoration { 

    def withMenuSimple(body: Future[List[SomeModel] => Result]):Future[Result] = { 
    val fm = getModelsFromDB 
    val fb = body 
    for { 
     m <- fm 
     b <- fb 
    } yield(b(m)) 
    } 
} 

Это должно выглядеть довольно хорошо знакомы с моей другой ответ, и он работает точно так же - он начнет выполнение и асинхронные задачи, объединяя их, как только они сделаны.

Action, который должен украсить шаблон с меню выглядит следующим образом:

class BlahController extends Controller with MenuDecoration { 

    def index = Action.async { 
    withMenuSimple { 
     getContent.map { content => implicit menu => 
     Ok(views.html.index(content)) 
     } 
    } 
    } 
} 

Почему withMenuSimple? Потому что в какой-то момент вы, вероятно, хотите, чтобы исследовать Request - поэтому у нас есть эта альтернатива:

trait MenuDecoration { 
    ... 

    def withMenu(body: RequestHeader => Future[List[SomeModel] => Result])(implicit request:RequestHeader):Future[Result] = { 
    val fm = fMenus 
    val fb = body(request) 
    for { 
     m <- fm 
     b <- fb 
    } yield(b(m)) 
    } 
} 

который вы бы использовать так:

def indexWithReq = Action.async { implicit request => 
    withMenu { req => 
    getContent.map { content => implicit menu => 
     Ok(views.html.index(content)) 
    } 
    } 
} 
+0

Спасибо большое! Сегодня многое узнали. Имейте мой upvote. – Roman

5

Определенно не очень хорошая идея, чтобы сделать шаблон приходится иметь дело с Future - поэтому вопрос становится один в вашем комментарии - (?) Как без blockingly получить содержание от вашего источника контента асинхронного, а также ваших пунктов меню из другого источника контента async?

for -comprehension на двух Future случаях делает трюк:

def index = Action.async { 
    val fContent:Future[Content] = getContent 
    val fMenus:Future[List[SomeModel] = getModelsFromDB 

    for { 
    content <- fContent 
    menus <- fMenus 
    } yield(Ok(views.html.index(content)(menus)))) 
} 

Примечание: Вы можете захотеть, чтобы попытаться спасти несколько строк и поместить вызовы методов (getContent, getModelsFromDB) прямо в блок for. К сожалению, пока он будет компилировать и работы, две задачи не будут работать параллельно, тем самым делая упражнение несколько бесполезным.

+0

Спасибо, дом. Точка передачи menuContext неявно заключается в том, что я хочу избежать, чтобы извлекать элементы меню в каждом действии вручную. 'menuContext' - это то, что должно быть доступно почти во всех представлениях. В идеале я вставляю menuContext в контроллер и позволяю scala implicits делать магию. – Roman