【问题标题】:Custom Actions with multiple implicit arguments具有多个隐式参数的自定义操作
【发布时间】:2013-08-03 11:34:48
【问题描述】:

我们的 Play 应用程序使用 Slick 作为数据访问层。这意味着在我们应用程序中的几乎每个操作中,我们都需要在作用域上隐式使用当前的 Request 和 Slick 的数据库 Session

我想编写一个自定义的Action 来执行此操作,因此我们只需要一行即可执行此操作。我想做的是以这样的方式写它,我可以写这样的东西:

def someAction = DBAction { implicit request, session =>
  // body with implicit request and session on scope

但这不是有效的语法。使用元组不起作用,因为它不能在动作主体中隐式解包元组。是否可以创建将多个隐式参数传递给正文的自定义操作?我该怎么做?

【问题讨论】:

  • 有两种方法可以实现这一点:一种 curryed 动作(Request[AnyContent] => Session => Result -> 请参阅下面的@DCKing 答案)或 WrappedRequest(请参阅我的答案)。

标签: scala playframework-2.0 playframework-2.1 slick


【解决方案1】:

你不能像那样隐含 2 个变量。

但是您的自定义操作可以返回一个WrappedRequest(一个封装请求和您的会话的对象),您可以定义这个封装的请求和您的会话之间的隐式转换。

试试这个例子,这个例子来自这个class

sealed case class DBRequest(session: Session, private val request: Request[AnyContent])
  extends WrappedRequest(request)

trait DBController extends Controller {

  // Implicit conversion from DBRequest to Session
  implicit def session(implicit request: DBRequest) = request.session

  def DBAction(action: DBRequest => Result) = Action { request =>
    database.withSession { session =>
      action(DBRequest(session, request))
    }
  }
}

object MyController extends Controller with DBController {

  def myAction = DBAction { implicit request =>
    println(session)
  }
}

【讨论】:

  • 好建议!我更喜欢 curried 解决方案,因为代码更简单并且不需要隐式转换魔法:)
  • 我喜欢这个版本,因为它避免了多个w => x => y => z。但是您的解决方案非常适合“2 级”操作!
【解决方案2】:

@senia 是对的,需要使用柯里化来做到这一点。这实际上是在 Play docs 中解决的,但这是我最近错过的一个补充。

为了供寻找此功能的人将来参考,我的自定义操作现在如下所示:

def DBAction(action: Request[AnyContent] => Session => Result) = {
  Action { request =>
    database.withSession { session =>
       action(request)(session)
    }
  }
}

然后我可以通过以下方式使用它:

def someAction = DBAction { implicit request => implicit session => /* body */ }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-17
    • 1970-01-01
    • 1970-01-01
    • 2018-07-05
    • 2015-09-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多