5

I'm currently using the session() of play framework in my template :

@if(session().get("email")==null){
    <li><a href="@controllers.routes.General.login">Login</a></li>
}else{
    <li><a href="@controllers.routes.General.logout">Logout</a></li>
}

This template is used in all of my views. Some of these views are controlled by a Java controller, and some are with a Scala controller.

When I click on links that lead to Java controllers, I have no problems, the links for login and logout are correctly handled.

When I click on links that lead to Scala controllers, I get a [RuntimeException: There is no HTTP Context available from here.]

From what I read in here about scala controllers, I understood that they didn't return the http context when rendering a page, but I really want to be able to use the session in my template.

I thought about using an argument session() in my view, templates and controllers, but I believe that there will be a conflict between the java session (play.mvc.http.session) and the scala session (play.api.mvc.session) when play will compile the html pages.

Am I stuck? Is there a possibility to force scala controllers to give back the http context ?

3 Answers 3

2

The root cause maybe the Java controllers and Scala controllers are handled differently. I have my project in Java first, and then try to add more Scala controllers. I also came across this problem (BTW, I am using Play 2.3.2).

I tried to fix this by setting my own Http.Context in the TheadLocal variable using my own ActionBuilder.

import play.api.mvc._
import scala.concurrent.Future
import play.mvc.Http.Context
import play.core.j.JavaHelpers

object ContextAction extends ActionBuilder[Request] {

  def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
    Context.current.set(JavaHelpers.createJavaContext(request))
    block(request)
  }
}

Then my Scala controller actions simply use this ContextAction instead:

class TestController extends Controller {
  def test = ContextAction { implicit request =>
    Ok(views.html.index())
  }
}

And this way the index template can access all request() / session() / etc.

Sign up to request clarification or add additional context in comments.

Comments

0

I may be wrong, but I think that your Scala controllers should look like:

  def myaction() = Action { implicit request =>
    ...
  }

instead of:

  def myaction() = Action {
    ...
  }

Ie, you have to add the request to the scope of your Action.

And add it also to your view, at the beginning of the file:

@(...)(implicit session:Session)

2 Comments

I thought that it would solve the problem too, and implicit request actually gives the controller the possibility to use the data in the http context. Unfortunatly, this data is not used by the scala controller to build the HTML page. (when doing Ok(...) , the data is not given to the page, so the problem is still here) I was also thinking that the #withSession was here for this, but it seems like it only gives back the HTTP header, AFTER having built the HTML page...
As I said, I can't use this solution. I use both scala and java versions of Session object : play.api.mvc.Session and play.mvc.Http.Sessionas I can only retrieve one of them in the scala or java controller (java controller returns java session, and scala controller returns scala session) When I declare one of these in my template (implicit session: play.mvc.Http.Session) the other is not working. And I can't simply put a (implicit session:Session) as the object Session is not found.
0

Okay I found a workaround this problem. This is not really aesthetic, but it works, and gets rid of the problem entirely.

I created two different main templates : scalamain.scala.html and javamain.scala.html.

The scalamain template is used by all views that are controlled by a Scala controller, and used the usual trick to use the session (implicit arguments, see more here).

The javamain template is used by all view that are controlled by a Java controller. (these view use the session easily).

The two templates are of course, the same once rendered by play.

I end up with some redundancy in my code and it took to separate all the actions so that view are controlled by only one type of controller(scala or java).

I hope this will help others with the same problem. I validate this answer, as it solves the problem, but feel free to answer if you find a more gracious way to solve it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.