Getting them to work well together was a bit of a challenge. Play! has a collection of modules in different states of development. I got the best results using the most recent releases at the moment: play 1.1, play-scala 0.8, and squeryl 0.9.4RC3. The most recent scalate module 0.7.2 was too old, and I had to use the development version from github and compile it myself.
Here is one issue I run into:
Given an example controller and action:
object Manage extends ScalateController {
def index = {
val someVar = getSomeObjectFromSomewhere()
Template(someVar)
}
}
The syntax hints that Template is an object that gets returned by the action. This is actually not correct. Play takes a bit of a strange approach when handling results in the controller. Result objects inherit from RuntimeException and are "thrown" from a controller's action and they are caught by framework. I suppose it makes it easy to break out of the flow in order to redirect, or something like that. So Template() is actually a method that "throws" a Result object.
This made it difficult at first to work with squeryl, which expects all database access to wrapper on a transaction{} block. For a whole day I kept trying to find the right way to do that trying different versions of the modules and different rendering methods. This was one of my attempts:
object Manage extends ScalateController {
def index = transaction {
// some squeryl database stuff
Template()
}
}
Of course it didn't work since the thrown results breaks the transaction. Then I created a base class that would catch and re-throw the result, something like this:
class MyBaseController extends ScalateController {
def Template (_args:Any*) {
var e:Result = null
transaction {
try {
super.Template(_args:_*)
} catch {
case r:Result => e = r
}
}
throw e
}
}
But that broke the "magic" parsing of local variables to send to the templates (maybe play does a little too much magic sometimes).
Finally I realized squeryl has a way to bind a session to the thread without using the transaction method. So, I was able to use that method and an @Before annotation to get the code to work:
class Manage extends ScalateController {
@Before
def initSquerylSession =
SessionFactory.newSession.bindToCurrentThread
def index = {
val projects = from(Repo.projects)(p =>
where(p.public === 1)
select(p)
).toList
Template(projects)
}
}
Hopefully this post will save someone some time.