Search code examples
scalaplayframeworkplayframework-2.2

Load the User object on each request in a controller, how to make this object available?


From what I understand controllers in play are singletons, so I'm not sure how to go about this.

In Rails I could simply load a user in the base_controller, and then in any controller that inherits from the base_controller the user object would be available for me to use.

In play, I'm not sure how this will work. Basically in each Action in a controller I want the user object to be available for me.

def someAction = {
    val name = user.name
    val age = user.age
    Ok("hello")
}

Is this possible in play? I'm' sure it is but I can't seem to figure out way to do this.


Solution

  • I'm not sure you'll be able to make it quite as terse as Rails, but using Play's Action Composition style you can build up something quite flexible.

    We start by creating a trait which knows how to build such a user, and wraps a normal Action, allowing the User to be obtained, and passed into the body:

    trait UserAware {
    
      def buildUserFromCookie(request:RequestHeader):Option[User] = {
    
        request.cookies.get("myUserCookie").map { c =>
          // Build up a User object from cookie contents
          // ...
        }
      }
    
      def cookieNotFound = Results.InternalServerError("Lost your session cookie :-(")
    
      def UserAction(f: User => Request[AnyContent] => SimpleResult):Action[AnyContent] =
        UserAction[AnyContent](BodyParsers.parse.anyContent)(f)
    
      def UserAction[T](bodyParser:BodyParser[T])(f: (User) => Request[T] => SimpleResult):Action[T] = {
        Action(bodyParser) { request =>
          buildUserFromCookie(request).fold(cookieNotFound) ({ user =>
            f(user)(request)
          })
        }
      }
    }
    

    I'm going to assume that you have a session cookie that holds sufficient information to be able to recreate a User object. Whatever you need to do within buildUserFromCookie() is out of scope here.

    I've defined two UserAction wrappers, one delegating to the other. The difference is whether you need a special body parser or not. Below you'll see it in use.

    The second UserAction method is the interesting one - if you supply it with a method that can take a User and a Request, it will call it for you after creating the user, or bombing out if it can't find the cookie.

    Here it is in use:

    object MyController extends Controller with UserAware {
    
      def doSomething = UserAction { implicit user => implicit request =>
        Ok(s"The user's name is $user.")
      }
    
      def doSomethingJsonish = UserAction(parse.json) { implicit user => implicit request =>
        Ok(s"The user's name is $user and their request body is JSON: ${request.body}")
      }
    }
    

    With the overloaded UserActions, you can still use Play's Body Parsers to get access to a nicely-typed request body, and you've got the freshly-created User available as user.