0
votes

I have a simple Play application in which I need to check url being called and use different database accordingly. I know that it's easy to access current url in the controller, but for this to work I need to access it in the model.

Passing the url from controller to each call of a model method would be too big of an inconvenience. Is there any other way to solve this problem?

Play Framework 2.2.1 / Scala 2.10.3

UPDATE: This is my basic example

Controller (Application.scala):

package controllers

import play.api._
import play.api.mvc._

import models.Data

object Application extends Controller {

    def index = Action {
        //Call to model method - model should somehow get the URL without it being passed as a param        
        val smth: String = Data.getSmth()
        Ok(smth);
    }

}

Model (Data.scala):

package models

object Data {

    def getSmth: Option[String] = DB.withSession {
        val db = //this is where I need the url to decide which database to use
        sql"""SELECT #$db.smth FROM smthTable""".as[String].firstOption
    }

}
1
I don't think it possible to access current url in model. Because the model does nothing to do with http. May be you can define an implicit request parameter in you model constructor. But I don't think this is a good idead. - jilen
@jilen How would I define that parameter in my model constructor? I still need to pass it or access it somehow. Surely, a situation like this shouldn't be uncommon? - Caballero
case class Foo(val bar: Int, val baz: String) case object Foo { def apply(bar: Int)(implicit request: play.api.mvc.Request[_]) = new Foo(bar, request.path) } something likes this, this is really not a good idea. - jilen
@jilen I don't think this is what I'm looking for. I must say I'm quite disappointed that such an obvious and common issue doesn't have a solution on Play. - Caballero
It has, you either pass it explicitly or you pass it implicitly. - johanandren

1 Answers

1
votes

So, this is by design in the Play Scala API - there is no magic context, if you want data you will have to pass it along to whatever piece of your code that needs it.

You will have to take the url as a parameter of some kind, you could do it like this:

case class MyModel(someData: String, requestUrl: String)

object MyModel {
  def apply(someData: String, request: Request) = 
    new MyModel(someData, request.url)
}

This would clearly express the dependency, but in your particular app you might call this from every request and want to avoid having to repeat providing that parameter, in that case you can use Scala implicits which makes the compiler look for a matching implicit instance that is of the same type in the current scope (you can read more about this here: http://www.scala-lang.org/old/node/114).

object MyModel {
  def apply(someData: String)(implicit request: Request) = 
    new MyModel(someData, request.url)
}

which could then be called from a controller action like this

def myAction = Action { implicit request => 
  val model = MyModel("blablabla")
  ...
}

Of course it may be a bad idea to tightly couple your model to the play Request API and you should probably introduce your own class to represent this 'context', you could then implicitly convert from Request to YourContext in you controllers and have the model implicitly use YourContext instead.

If all this sounds like gibberish to you, you should probably start with actually learning Scala before trying to build a web app in Scala. There are lots of good books nowadays ('Scala for the impatient' for example) as well as a multitude of good online resources (the neophytes guide to scala is a good one).

Good luck!