Caballero
Caballero

Reputation: 12091

Scala/Play: access current url in a model

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
    }

}

Upvotes: 0

Views: 1004

Answers (1)

johanandren
johanandren

Reputation: 11479

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!

Upvotes: 1

Related Questions