7

リクエストに基づいてデータを入力し、コントローラーに渡すためplay.api.mvc.Actionに使用できるカスタムを作成しようとしています。CustomerAccountCustomerAccount

Play 2.2.xのドキュメントに従ってActionandを作成しましたが、アクション内で fromActionBuilderを返すことができないようです。CustomerAccount

私の現在のコードは次のとおりです。

case class AccountWrappedRequest[A](account: CustomerAccount, request: Request[A]) extends WrappedRequest[A](request)

case class Account[A](action: Action[A]) extends Action[A] {
  lazy val parser = action.parser

  def apply(request: Request[A]): Future[SimpleResult] = {
    AccountService.getBySubdomain(request.host).map { account => 
      // Do something to return the account like return a new AccountWrappedRequest?
      action(AccountWrappedRequest(account, request))
    } getOrElse {
      Future.successful(NotFound(views.html.account_not_found()))
    }
  }
}

object AccountAction extends ActionBuilder[AccountWrappedRequest] { 
  def invokeBlock[A](request: Request[A], block: (AccountWrappedRequest[A]) => Future[SimpleResult]) = {
    // Or here to pass it to the next request?
    block(request) // block(AccountWrappedRequest(account??, request))
  }

  override def composeAction[A](action: Action[A]) = Account(action) 
}

注:block(request)関数はAccountWrappedRequest入力できない型を想定しているため、これはコンパイルされません。ストレートを使用するとコンパイルされますRequest

さらに...

最終的には、このアカウント アクションを認証アクションと組み合わせて、認証アクションCustomerAccountに渡して、その顧客のアカウントに基づいてユーザー認証を提供できるようにしたいと考えています。次に、顧客アカウントとユーザーをコントローラーに渡します。

例えば:

Account(Authenticated(Action))) { request => request.account; request.user ... }カスタムリクエストオブジェクトを必要としない個々のオブジェクトとして。

4

2 に答える 2

4

これが最善の方法かどうかはわかりませんが、かなりうまくいくと思われる解決策を思いつくことができました。

キーは、次のリクエストに渡す前に、それをAccountWrappedRequest内部に変換するリクエストで一致することでした。invokeBlockチェーン内の別のアクションがチェーン内の以前のアクションからの値を予期している場合、同様にリクエストを照合して、リクエスト パラメータにアクセスするために必要なタイプに変換できます。

元の質問から例を更新する:

case class AccountWrappedRequest[A](account: CustomerAccount, request: Request[A]) extends WrappedRequest[A](request)

case class Account[A](action: Action[A]) extends Action[A] {
  lazy val parser = action.parser

  def apply(request: Request[A]): Future[SimpleResult] = {
    AccountService.getBySubdomain(request.host).map { account => 
      action(AccountWrappedRequest(account, request))
    } getOrElse {
      Future.successful(NotFound(views.html.account_not_found()))
    }
  }
}

object AccountAction extends ActionBuilder[AccountWrappedRequest] { 
  def invokeBlock[A](request: Request[A], block: (AccountWrappedRequest[A]) => Future[SimpleResult]) = {
    request match {
      case req: AccountRequest[A] => block(req)
      case _ => Future.successful(BadRequest("400 Invalid Request"))
    }
  }

  override def composeAction[A](action: Action[A]) = Account(action) 
}

次にapply()、別のアクション(私の場合は認証済みアクション)のメソッド内で、同様に行うことができます:

def apply(request: Request[A]): Future[SimpleResult] = {
  request match {
    case req: AccountRequest[A] => {
      // Do something that requires req.account
      val user = User(1, "New User")
      action(AuthenticatedWrappedRequest(req.account, user, request))
    }
    case _ => Future.successful(BadRequest("400 Invalid Request"))
  }
}

そして、ActionBuilder でアクションを連鎖させることができます

override def composeAction[A](action: Action[A]) = Account(Authenticated(action))

AuthenticatedWrappedRequestがコントローラに渡された場合request.accountrequest.userおよび通常のすべてのリクエスト パラメータにアクセスできます。

ご覧のとおり、応答が不明な場合がいくつかあり、BadRequest. 実際には、私が知る限り、これらは決して呼び出されるべきではありませんが、念のためそこにあります。

私はまだScalaにかなり慣れていないため、このソリューションについてフィードバックをいただければ幸いです。同じ結果を得るより良い方法があるかどうかはわかりませんが、これが誰かにも役立つことを願っています.

于 2013-11-06T22:45:21.860 に答える