【问题标题】:How to pass flash data from controller to view with Play! framework如何将闪存数据从控制器传递到使用 Play 进行查看!框架
【发布时间】:2013-03-10 00:20:28
【问题描述】:

我一直在玩游戏!到目前为止,学习曲线有一些颠簸。现在我无法将闪存数据从控制器传递到视图,起初我认为这是一项微不足道的任务,或者至少应该如此。

这是我现在拥有的:

我有一个主布局:application.scala.html

我在布局中有一个视图:login.scala.html

我有我的控制器和方法:UX.authenticate() - 我希望它根据登录尝试的结果(成功与失败)向视图提供闪存数据

这是我的控制器方法中的代码:

def authenticate = Action { implicit request =>
        val (email, password) = User.login.bindFromRequest.get
        // Validation
        // -- Make sure nothing is empty
        if(email.isEmpty || password.isEmpty) {
            flash + ("message" -> "Fields cannot be empty") + ("state" -> "error")
            Redirect(routes.UX.login())
        }
        // -- Make sure email address entered is a service email
        val domain = email.split("@")
        if(domain(1) != "example.com" || !"""(\w+)@([\w\.]+)""".r.unapplySeq(email).isDefined) {
            flash + ("message" -> "You are not permitted to access this service") + ("state" -> "error")
            Redirect(routes.UX.login())
        } else {
            // Attempt login
            if(AuthHelper.login(email, password)) {
                // Login successful
                val user = User.findByEmail(email)
                flash + ("message" -> "Login successful") + ("state" -> "success")
                Redirect(routes.UX.manager()).withSession(
                  session + (
                    "user"      -> user.id.toString
                  )
                )
            } else {
                // Bad login
                flash + ("message" -> "Login failed") + ("state" -> "error")
                Redirect(routes.UX.login())
            }
        }
    }

在我的登录视图中,我有一个参数:@(implicit flash: Flash)

当我尝试使用 flash 时,使用 @flash.get("message") 没有出现任何内容

理想情况下,我想在布局中设置@(implicit flash: Flash),这样我就可以从任何控制器刷新数据,它会到达我的视图。但是每当我这样做时,登录视图都会引发错误。

在我现在的登录视图中,我有这个:

def login = Action { implicit request =>
        flash + ("message" -> "test")
        Ok(views.html.ux.login(flash))
    }

将闪存数据传递到视图的理想方式是什么,是否有任何示例? Play 中的示例!框架文档没有任何帮助,并且仅限于两个根本不显示与视图交互的示例(在底部找到:http://www.playframework.com/documentation/2.0/ScalaSessionFlash)。

有没有更简单的选择?我究竟做错了什么?如何将 Flash 数据直接传递到我的布局视图?

【问题讨论】:

    标签: scala playframework playframework-2.0


    【解决方案1】:

    如果您查看 Session and Flash scopes 的文档,您会看到以下代码 sn-p:

    def save = Action {
      Redirect("/home").flashing(
        "success" -> "The item has been created"
      )
    }
    

    现在,将其与您使用的闪光灯范围进行比较:

    flash + ("message" -> "Login successful") + ("state" -> "success")
    

    这种用法的问题是 flash 是不可变的,您无法重新分配它。此外,您在这里的使用实际上是在创建一个新的 flash 变量,它只是没有被使用。

    如果你稍微修改一下变成:

    implicit val newFlash = flash + ("message" -> "Login successful") + ("state" -> "success")
    Redirect(...)
    

    它会起作用的。但是,首选用法是对结果使用 .flashing() 方法。此方法来自 play.api.mvc.WithHeaders,这是一个混入 play.api.mvc.PlainResult 的特征,各种结果方法(Ok、Redirect 等)都继承自该特征。

    然后,如文档中所示,您可以访问模板中的 flash 范围:

    @()(implicit flash: Flash) ... 
    @flash.get("success").getOrElse("Welcome!") ...
    

    编辑:啊,好吧。我已经查看了您的示例代码,现在我看到了您要执行的操作。我认为您真正要寻找的是处理表单提交的规范方式。查看文档中的约束定义here,我想您会发现有更好的方法来实现这一点。本质上,您需要在支持表单的元组上使用 verifying 方法,这样 bindFromRequest 将无法绑定,并且可以将验证错误传递回视图:

    loginForm.bindFromRequest.fold(
      formWithErrors => // binding failure, you retrieve the form containing errors,
        BadRequest(views.html.login(formWithErrors)),
      value => // binding success, you get the actual value 
        Redirect(routes.HomeController.home).flashing("message" -> "Welcome!" + value.firstName)
    )
    

    【讨论】:

    • flashing() 方法有效,但是我如何将闪存数据放入我的布局中,而不必将其从控制器传递到我的视图,然后再传递到我的布局?
    • 假设您在这里有两个视图:login.scala.htmllayout.scala.html。你试图从你的控制器调用views.html.login(...),然后看起来像@layout { form stuff } 。如果您还在布局视图中将flash 声明为隐式变量,它将自动在您的布局范围内。这就是你要找的东西吗?
    • 在几乎完全相同的情况下,我得到了这个错误'=>' expected but ')' found. - 你的例子和我的设置的例外是我的布局有参数所以从login.scala.html它看起来像这样:@layout(param) { content } 所以在我的layout.scala.html 我有这个:@(title: String)(content: Html) \n @(implicit flash: Flash) - 我在这里做错了什么?
    • 删除了参数并按照示例中的方式设置它现在我收到此错误:could not find implicit value for parameter flash: play.api.mvc.Flash
    • layout.scala.html 的参数应该是@(title: String)(content: Html)(implicit flash: Flash)。它们之间没有换行符。
    【解决方案2】:

    想在此讨论中再添加一件事,以帮助人们避免此错误:

    could not find implicit value for parameter flash: play.api.mvc.Flash
    

    我知道这很多都是多余的,但最后有一个技术问题占用了我一半的工作日,我觉得我可以帮助人们解决这个问题。附加 .flash(/* 你的 flash 作用域信息 */),如:

    Redirect(routes.ImageEditApp.renderFormAction(assetId)).
      flashing("error" -> "New filename must be unused and cannot be empty.")
    

    ... 确实 定义了可以在模板中使用的隐式“flash”变量,如果您有一个“基本”模板要用于处理 flash 范围(例如错误) , single 基本模板的使用很容易,因为您已经通过 .flashing() 定义了隐式 flash 变量...这是我的基本模板“包含”之一的示例。

    @views.html.base("Editing: "+asset.id, scripts = Some(scripts),
      extraNav = Some(nav))
    

    您确实不必必须将“flash”变量传递给基本模板。这是一个隐含的。基本模板仍然必须定义它。我的基本模板的参数是这样的:

    @(title: String, stylesheets: Option[Html] = None,
      scripts: Option[Html] = None,
      extraNav: Option[Html] = None)(content: Html)(implicit flash: Flash)
    

    是的,我知道其中很多内容是不必要的,但这是我复制粘贴的真实示例。无论如何,您可能需要其他模板来使用您的基本模板,并且您并不总是使用 .flashing() 来加载它们。由于您肯定会使用控制器加载这些,因此如果您忘记使用 implicit request => 为每个操作启动您的操作,例如:

    def controllerMethodName() = Action { implicit request =>
    

    那么“flash”隐式将不会被定义。然后,当该模板尝试包含您的基本模板时,您会感到困惑,因为您没有定义 default flash 隐式变量,而基本模板需要它。因此出现了这个错误。

    再一次,修复.. 转到您所有的控制器方法,并确保您输入了那个隐式请求 =>

    【讨论】:

    • 你为我节省了一个小时 :) 谢谢!
    猜你喜欢
    • 2019-01-01
    • 2019-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-11
    • 1970-01-01
    相关资源
    最近更新 更多