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?
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?:
- First look in current scope
- Implicits defined in current scope
- Explicit imports
- wildcard imports
- 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 bindFormRequerst
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With