Scala Play 2.5 Form bindFromRequest: Cannot find any HTTP Request here?
Asked Answered
B

2

6

I have one controller action implemented like this:

def doChangePassword = deadbolt.Restrict(List(Array(Application.USER_ROLE_KEY)))() 
{ request => // <<<<<<<<<<<< here is the request 
  Future {
    val context = JavaHelpers.createJavaContext(request)
    com.feth.play.module.pa.controllers.AuthenticateBase.noCache(context.response())

    val filledForm = Account.PasswordChangeForm.bindFromRequest
    // compilation error here, it can't see the request ^^^^^^^

    if (filledForm.hasErrors) {
      // User did not select whether to link or not link
      BadRequest(views.html.account.password_change(userService, filledForm))
    } else {
      val Some(user: UserRow) = userService.getUser(context.session)
      val newPassword = filledForm.get.password
      userService.changePassword(user, new MyUsernamePasswordAuthUser(newPassword), true)
      Redirect(routes.Application.profile).flashing(
        Application.FLASH_MESSAGE_KEY -> messagesApi.preferred(request)("playauthenticate.change_password.success")
      )
    }
  }
}

the implementation above leads to the compilation error:

[error] /home/bravegag/code/play-authenticate-usage-scala/app/controllers/Account.scala:74: Cannot find any HTTP Request here
[error]         val filledForm =  Account.PasswordChangeForm.bindFromRequest
[error]                                                     ^
[error] one error found

However, if I change line 2 from:

{ request => // <<<<<<<<<<<< here is the request 

to

{ implicit request => // <<<<<<<<<<<< here is the request 

then it compiles ... but why?

Brassbound answered 11/12, 2016 at 20:42 Comment(1)
A request is required to be in the implicit scope. Without, it doesn't compile.Carboloy
P
8

What you are looking for are Implicit Parameters. In short:

Implicit Parameters can be passed just like regular or explicit parameters. In case you do not provide an implicit parameter explicitly, then the compiler will try to pass one for you. Implicits can come from various places. From the FAQ Where does Scala look for implicits?:

  1. First look in current scope
  • Implicits defined in current scope
  • Explicit imports
  • wildcard imports
  1. Now look at associated types in
  • Companion objects of a type
  • Implicit scope of an argument’s type (2.9.1)
  • Implicit scope of type arguments (2.8.0)
  • Outer objects for nested types
  • Other dimensions

Implicits under number 1. take precedence over those under number 2.

By marking request as implicit in your example, you are declaring an "Implicit defined in current scope". You need to have an implicit request in place because bindFormRequest "asks" you to pass one. See its signature:

bindFromRequest()(implicit request: Request[_]): Form[T]

Now that you have an implicit request in scope, the compiler will automatically pass it to bindFromRequest.

As I mentioned in the beginning, you could also pass request explicitly:

val filledForm = Account.PasswordChangeForm.bindFromRequest()(request)

In the latter case there is no need to declare request as implicit as you are obviously passing request explicitly. Both variants are equal. It's up to you which one you prefer.

Puseyism answered 12/12, 2016 at 8:21 Comment(0)
L
2

you need an implicit request in scope, like this: https://github.com/pedrorijo91/play-slick3-steps/blob/master/app/controllers/ApplicationController.scala#L11

Livi answered 11/12, 2016 at 21:25 Comment(2)
that's the code for a Play app tutorial I did a while ago. I also wrote a blog post, which may cover some of the difficulties you may find. Hope it may help you pedrorijo.com/blog/play-slickLivi
Yes I got that ... but language-wise what does it mean to have a parameter like request in this case qualified as implicit?Brassbound

© 2022 - 2024 — McMap. All rights reserved.