我一直在玩耍!到目前为止,学习曲线有一些障碍。现在我无法将闪存数据从控制器传递到视图,起初我认为这是一项微不足道的任务,或者至少它应该是。
这就是我现在所拥有的:
我有一个主要的布局:application.scala.html
我在布局中有一个视图:login.scala.html
我有我的控制器和方法:UX.authenticate() - 我想根据登录尝试的结果(成功与失败)向视图提供flash数据
这是我的控制器方法中的代码:
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.get("message")
理想情况下,我想在布局中设置@(implicit flash: Flash)
,这样我就可以从任何控制器中刷新数据,它就会到达我的视野。但每当我这样做时,登录视图都会抛出错误。
我现在的登录视图中有这个:
def login = Action { implicit request =>
flash + ("message" -> "test")
Ok(views.html.ux.login(flash))
}
将Flash数据传递到视图的理想方式是什么?有哪些示例?关于Play的例子!框架文档没有任何帮助,仅限于两个与视图完全没有交互的示例(位于底部:http://www.playframework.com/documentation/2.0/ScalaSessionFlash)。
有更简单的选择吗?我究竟做错了什么?如何将Flash数据直接传递到布局视图?
答案 0 :(得分:8)
如果您查看Session and Flash scopes的文档,您会看到以下代码段:
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)
)
答案 1 :(得分:5)
希望在此次讨论中再添加一个内容,以帮助人们避免此错误:
could not find implicit value for parameter flash: play.api.mvc.Flash
我知道其中很多都是多余的,但是最后有一个技术性,偷走了我工作日的一半,我觉得我可以帮助别人。附加.flashing(/ *你的flash范围信息* /),例如:
Redirect(routes.ImageEditApp.renderFormAction(assetId)).
flashing("error" -> "New filename must be unused and cannot be empty.")
... 确定定义您可以在模板中使用的隐式“flash”变量,如果您有一个“基础”模板,您希望处理闪存范围(例如错误) ,单个基本模板的使用很容易,因为你已经通过.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)
是的,我知道很多事情是不必要的,但这是一个真实世界的例子,我正在复制n'粘贴。无论如何,您可能需要使用基本模板的其他模板,而并不总是使用.flashing()来加载它们。由于您肯定会使用控制器加载这些内容,因此如果您忘记使用隐式请求=> 启动每个操作,例如:
def controllerMethodName() = Action { implicit request =>
然后不会定义隐含的“flash”。然后,当该模板试图包含您的基本模板时,您将陷入困境,因为您没有定义默认flash 隐式变量,而基本模板需要它。因此错误。
再次,修复..转到所有控制器方法,确保你输入隐含请求=> !