[2.0] Getting access to the currently executing request in Scala for controller methods that return Html instead of Actions

1,436 views
Skip to first unread message

Geoff Horsey

unread,
Apr 21, 2012, 4:00:17 PM4/21/12
to play-fr...@googlegroups.com
Hi all,

I've got a quick question.  Within a method, that is called during the fulfillment of a request, is it possible to get the currently executing request from the executing context?

The use case I'm working on here is something that could be satisfied by what's called a child action method in the ASP.Net MVC world.  In which, from within a view you call a method on a controller which has full access to the HTTP context it is executing within and it returns a View.

I realized in my exploration of the play 2.0 framework, that you don't need any additional concept to the framework to achieve the same functionality, by creating a method on the controller that returns an Html object (like a standard view method).  In this way, you can keep controller logic in the controller (fetching a required object for example) and view logic (presenting the fetched object).

A real simple example would be, say you wanted to produced a list of categories that would be reused and placed on many pages.  You'd create the view categories.scala.html:
@(categories: Seq[Category])
<ul>...code to produce list of categories</ul>

Now on each page that wanted to use this sub-view, you'd need fetch the categories in each action method and pass them into view, which internally would forward them into the @categories sub-view.  It's this repetitive fetching code and passing around I want to remove, and can be removed in the play framework by by writing the following action method:
def produceCategories = {
  html.categories(categoryDao.all)
}

Then in the view that needs to display this list, you can remove the Seq[Category] argument that would be required to pass into the categories.scala.html view and simply call @controller.productCategories.  Win, win, win. 

Now my snag.

Setup: I have a master layout view, which has a header that changes depending on whether or not a user is logged in.  This is a layout view that is used by virtually all other views on my site.  Instead of having to fetch the current user in each and every action method of the site, just so the Option[User] can be passed into each and every view of the site so that the master layout view can display a logout button when a user is logged in.  I'd like to have an HTML method on my main controller which can fetch the user from the request, load them from the db and pass the Option[User] once into a view called header

View method on controller:
def productHeader(): play.api.templates.Html = {
  val user = // code that fetches the username from the auth cookie, loads them from the database
  // How can I get access to the current request?
  views.html.header(user) // return the view that produces the correct html when we have a user or when we have none.
}

in the main layout view I can simply call:
@application.productHeader
once and no additional code is needed anywhere else.

win, win, snag... I don't see how I can get access to the current request implicitly.  I think in the java version they have Http.Request.current or something.
  • The best possible outcome is there is a context object somewhere (undocumented/that I haven't found) that has access to the currently executing request (or is None/null if no request can be found)
  • The second best possible outcome is to use the implicit resolution of the request on the views.

While writing this post, I have gotten the second option to work:
  1. The html view method in the controller is 'def productHeader(implicit request: Request[AnyContent]): play.api.templates.Html = { /*...*/ }`
  2. Each action method I have to do `def someAction() = Action { implicit request => /*reset of the code */ }
  3. Each view I must include in the view signature @(someViewArg:String)(implicit request: Request[AnyContent]) ...

Having a context registry object where I could fetch the current request could remove all of repeated code that is just used to wire a request object into a method.

Does that context object exist for the scala version of the framework?

If not, can there be plans added to include it in a subsequent release?

Julien Richard-Foy

unread,
Apr 21, 2012, 5:32:06 PM4/21/12
to play-fr...@googlegroups.com
On Sat, Apr 21, 2012 at 10:00 PM, Geoff Horsey <geoff....@gmail.com> wrote:
> Hi all,
>
> I've got a quick question.

[…]

> Does that context object exist for the scala version of the framework?

No.

> If not, can there be plans added to include it in a subsequent release?

No, because thanks to implicit parameters this context object can be
avoided in Scala.
Just make your productHeader method take an implicit Request and you’re done.

You may also be interested in reading this:
http://stackoverflow.com/questions/9629250/how-to-avoid-passing-parameters-everywhere-in-play2/9632085#9632085

Geoff Horsey

unread,
Apr 21, 2012, 7:00:52 PM4/21/12
to play-fr...@googlegroups.com
My experience with the implicit parameter doesn't quite match what you say.

That was the first thing I tried.

def productHeader(implicit request: Request[AnyContent]).

Then without any changes to the public.scala.html file, I called:
@()
<html><body>
@controller.productHeader
</body></html>

Doing just these 2 things I got the following error:
"Cannot find any HTTP Request here"

So I had to modify the signature to public.scala.html:
@(implicit request: Request[AnyContent])
<html><body>
@controller.productHeader
</body></html>

Then for each page that uses the public.scala.html view, I had to start dragging around the implicit request in the view signature...
login.scala.html
@(implicit request:Request[AnyContent])
@public {
  <p>Login html stuffs</p>
}

When using the implicit argument, the only benefit is that I don't have to specify @public(request) { ... }  in login.scala.html, and in public.scala.html, I don't have to specify @controller.produceHeader(request).  Since you still have to include the implicit argument to each view, there's really no savings.

So if it worked like you suggested and the only code i had to add was an implicit argument for the request on the method and didn't have to modify the signatures of any of the view field, then yes, epic win!

But if it's not, I'd rather have a context object and not have to add that extra implicit argument to the signature of each view.  Also, having the context object would allow my little `produceHeader` function operate more autonomously and not depend on the implicit injection of that silly argument.

So I would still vote for a context object that can give the current information for the executing request.

Unless what I have found is a bug, and it should work just like you said, without having to also include that implicit argument to each and every view, in addition to the method.

If you will always need to specify the implicit argument for each and every view, then there's no benefit to using implicit and you might as well make the argument explicit and pass it around. (The savings of being able to call a method w/out the argument  but sill needing to specify a parameter in the definition of the view is no savings at all.  Well I guess it could be, if the implicit argument was passed to many many methods within a single view.  Then not having to type the same argument a many many times would be a savings).

I would still up vote a context object for scala! :)

BTW, awesome work on this framework... I'm still new to scala so smack me in the face if I'm just misguided about this! 

(It's a minor savings on complexity I'm arguing for here, it's livable having to specify the implicit parameter for each and every view)

G~


On Saturday, April 21, 2012 2:32:06 PM UTC-7, Julien Richard-Foy wrote:

Julien Richard-Foy

unread,
Apr 22, 2012, 4:41:55 AM4/22/12
to play-fr...@googlegroups.com
> Also, having the
> context object would allow my little `produceHeader` function operate more
> autonomously and not depend on the implicit injection of that silly
> argument.

I don’t know Guillaume’s or Sadek’s point of view, but IMHO it’s
better to declare every function dependencies in its parameters
instead of letting it access global variables. It makes the code
easier to reason about and less fragile because its dependencies are
more visible.

Guillaume Bort

unread,
Apr 22, 2012, 5:18:25 AM4/22/12
to play-fr...@googlegroups.com, play-fr...@googlegroups.com
Of course declaring its own input parameters is the way to go. It allows the compiler to check the logic of your action/templates composition.

Accessing a global context from anywhere is not something we want for the Scala API.
> --
> You received this message because you are subscribed to the Google Groups "play-framework" group.
> To post to this group, send email to play-fr...@googlegroups.com.
> To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.
>

Pascal Voitot Dev

unread,
Apr 22, 2012, 7:30:22 AM4/22/12
to play-fr...@googlegroups.com
Guillaume, I agree with you but I have a question.
Last week, Etienne had an idea and we were discussing how to do it in Play2 but we couldn't really find a clever way.

Imagine we want to create a utility template such as an automatic development footer containing lots of info about your session/request/response/headers (targetting info seen from Play2 side). Such tools can be found in rails frameworks. This devFooter would be activated only in dev mode for example.

You could activate this dev footer by calling it in the main.scala.html or even in a more natural way, activating it in a configuration.
But this template would require lots of implicits:
@devFooter()(implicit request, response, session ...)

But this requires that you explicitly put those implicits in all your own templates definitions calling @main().
We tried to find a better way to do it because it seems quite obvious not to ask users to add implicits in their templates while they don't care about them in their real templates.

How would you do that?

Thanks
Pascal

Julien Richard-Foy

unread,
Apr 22, 2012, 7:57:48 AM4/22/12
to play-fr...@googlegroups.com
I’m not Guillaume but here’s how I would handle this case: I would
have a state only for my development plugin. This state would be set
for each request using the Global#onRouteRequest hook. It would *not*
allow to see response headers though.

Ricky Elrod

unread,
Apr 22, 2012, 8:02:11 AM4/22/12
to play-fr...@googlegroups.com
On Saturday, April 21, 2012 7:00:52 PM UTC-4, Geoff Horsey wrote:
Then for each page that uses the public.scala.html view, I had to start dragging around the implicit request in the view signature...
login.scala.html
@(implicit request:Request[AnyContent])
@public {
  <p>Login html stuffs</p>
}

When using the implicit argument, the only benefit is that I don't have to specify @public(request) { ... }  in login.scala.html, and in public.scala.html, I don't have to specify @controller.produceHeader(request).  Since you still have to include the implicit argument to each view, there's really no savings.

So if it worked like you suggested and the only code i had to add was an implicit argument for the request on the method and didn't have to modify the signatures of any of the view field, then yes, epic win!


+100. I just ran into this very issue. It would be great if there could be a @request variable that is always guaranteed to be there, much like @routes and @play is. This would save a lot of headache.

Pascal Voitot Dev

unread,
Apr 22, 2012, 8:01:53 AM4/22/12
to play-fr...@googlegroups.com
I see...
But the idea is also to see the session after the action... you can see the request/response on browser side but I'm more interested in the data on server side!

Pascal

Geoff Horsey

unread,
Apr 22, 2012, 1:04:15 PM4/22/12
to play-fr...@googlegroups.com
I'm glad that another use case has come up where it would be nice to have access to the execution context from within a view without having to pass the context around as parameters.  I am sure there are many more, outside of the two that have come up from this thread.

The point on autonomy for a method was poorly thought out and made (my bad).  I do agree that using global variables is a bad practice, especially mutable global variables.

But there are design patterns around, such as the Registry pattern, that allow controlled access to global variables because when used judiciously, is beneficial.

Perhaps a compromise would be some way to create an immutable context object that has read-only information pertaining to the currently executing request.

In my case, I just want read access to an authentication cookie without having to include implicit Request[AnyContent]  around each and every view I create.
It sound like in Pascal's case, he wants access to the request/response/session/headers, so that he can produce a developer console at the bottom of each page, again w/out forcing the developer to drag around the implicit request variables.

G~


On Sunday, April 22, 2012 5:01:53 AM UTC-7, Pascal wrote:
I see...
But the idea is also to see the session after the action... you can see the request/response on browser side but I'm more interested in the data on server side!

Pascal

On Sun, Apr 22, 2012 at 1:57 PM, Julien Richard-Foy wrote:
I’m not Guillaume but here’s how I would handle this case: I would
have a state only for my development plugin. This state would be set
for each request using the Global#onRouteRequest hook. It would *not*
allow to see response headers though.

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To post to this group, send email to play-framework@googlegroups.com.
To unsubscribe from this group, send email to play-framework+unsubscribe@googlegroups.com.

Julien Richard-Foy

unread,
Apr 22, 2012, 2:11:26 PM4/22/12
to play-fr...@googlegroups.com
> +100. I just ran into this very issue. It would be great if there could be a
> @request variable that is always guaranteed to be there, much like @routes
> and @play is. This would save a lot of headache.

But you can’t guarantee there always is a Request. For instance you
could use the template engine from a background job.

Geoff Horsey

unread,
Apr 22, 2012, 2:26:41 PM4/22/12
to play-fr...@googlegroups.com
True.  Returning something like an Option would suffice.  If the context doesn't exist, return None and let the developer using the framework deal with it.

I think access to the request context from within only a controller would suffice. (I've never written a module or even looked at the documentation, so I don't know if there is a different object type that modules would use which would benefit from this sort of access).

Other frameworks, like rails and ASP.Net MVC, include the request context (access to request/response/session/etc) as properties of a controller.  But in the case of those frameworks, I think the controller objects are created and destroyed on a per request basis.

Is there maybe also an architectural challenge, in that controllers in Play are singletons, and it would be difficult to map the current execution of a request, outside of the chain of methods that are triggered once an action is invoked?

(Again still new to scala and play, so not sure if there is some scala magic or functional design pattern that I don't know about which could solve this).

G~

Julien Tournay

unread,
Apr 24, 2012, 4:16:06 PM4/24/12
to play-fr...@googlegroups.com
Hi,

| But the idea is also to see the session after the action... you can see the request/response on browser side but I'm more interested in the data on server |  | side!

You can't. The template is rendered before the response is sent back. You could have a Global messing with the response even after the Action has returned a result.

jto.

Le dimanche 22 avril 2012 05:01:53 UTC-7, Pascal a écrit :
I see...
But the idea is also to see the session after the action... you can see the request/response on browser side but I'm more interested in the data on server side!

Pascal

On Sun, Apr 22, 2012 at 1:57 PM, Julien Richard-Foy <j...@zenexity.com> wrote:
I’m not Guillaume but here’s how I would handle this case: I would
have a state only for my development plugin. This state would be set
for each request using the Global#onRouteRequest hook. It would *not*
allow to see response headers though.

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To post to this group, send email to play-framework@googlegroups.com.
To unsubscribe from this group, send email to play-framework+unsubscribe@googlegroups.com.

Sadache Aldrobi

unread,
Apr 25, 2012, 5:36:10 AM4/25/12
to play-fr...@googlegroups.com
What about in the global, get back the reponse and check if it is HTML then add the footer?

To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/NmYtRmjlFogJ.

To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.



--
www.sadekdrobi.com
ʎdoɹʇuǝ
Reply all
Reply to author
Forward
0 new messages