Office of Secret Intelligence

Who taught you to be a spy, fucking Gallagher!?!

Playing With Scala: Building a Small Web App with Play 2.4, Play-Slick and Postgres

UPDATE: This isn't a full tutorial. I plan on doing this in pieces. The code shown here is one example of one piece of the app. I'll delve more into the code later, but I thought that the issues I encountered while getting up and going were more important to write about initially. I hope that's not too confusing.


 

 

It's been a while, but I finally have something interesting to write about.

 

I've been dabbling with the Play framework again after some time.  Work uses Java for a whole lot of stuff so I figured it'd behoove me to ease myself into the JVM again.  I don't know Scala very well, but after a foray into Go and C#, looking at it now makes a lot more sense than when I first looked at it.

I decided that I wanted to write a workout progress tracker.  I'm getting married in August and I made it a goal a while back to put on some muscle weight, and put on some weight on the bar.  I'd been struggling and struggling to get more weight up on the bar, and just couldn't be consistent.  Long story short, it turns out a lot of it was my diet, probably almost all of it (but that's another story).  My lifts started improving, I gained about 10-12 pounds, and I decided I wanted to see how far I've come since I started officially lifting again a few years ago.

 

A few things have changed since I last looked at Play.  For one, it uses the activator system to scaffold apps, run tests, install scala, etc.  It's a little confusing, but really it's not so bad.  I also had intended on using squeryl for my database object stuff, but it looks like it hasn't been updated in a while and I remembered the agonizing pain I went through just to get it to work at all the last time I did this. So, I went with slick, play's endorsed ORM FRM.  Specifically, I went with play-slick, which integrates slick directly into play itself.  

This was a little bit of a nightmare at first, because the tutorial for play initially sets you up with play 2.3.8 by default, and I wanted to be using the latest play-slick, as those docs seemed the most robust and up to date, which requires: 

  1. Play version 2.4.x
  2. Slick version 3.0.x
  3. Scala version 2.10.x/2.11.x

The issue I ran into, that frustrated me to no end, was the fact that the tutorials don't specify which specific versions of each you need.  I just looked through my commit history to try to find specifics, and I started convulsing, so long story short: if you're getting a lot of errors trying to find dependencies, make sure your build.sbt has at least a couple resolvers for the typesafe repository, and google the latest version for your dependency and try using that.  Here are my plugin.sbt and build.sbt for reference (I went ahead and made a gist so that they remain tied to this post's version, here's the repo in case you are from the future and want to see something that may be more up to date: https://github.com/dhoss/steel): https://gist.github.com/dhoss/1a824ee5397f22eec0ac.

ANOTHER NOTE BEFORE I GO FURTHER: I felt like a complete idiot for this, but adding a resolver in plugins.sbt doesn't necessarily mean it's going to be available in build.sbt.  I'm sure this is incredibly naive and dumb, but I spent a lot of time yelling at my screen trying to figure out why nothing was being pulled down from the repo I had just added.  I ended up just adding the resolvers to both build.sbt and plugins.sbt.  Like they say, "shoot 'em all and let God sort 'em out."

 

The last thing I really needed to get sorted was this nagging issue where my app couldn't connect to postgres.  Postgres was running, I could connect to it using the same username and password, but the app couldn't do it. Again, this was something minor that turned out to be in front of my face the whole time, but because I wasn't able to find a lot of documentation on slick driver connection configuration.  This one line was all that was standing between me and glory:

 This needs to go before a line that looks like this:

 

This really confused me for a while, so I can help keep others from this same frustration.

Moving on to some code.

Make sure you read through this and get everything set up first: https://www.playframework.com/documentation/2.4.x/Home 

I decided to go with a DAO set up for my database access, because the initial code I was following  is set up as such and it seemed reasonably simple and flexible.  You do have to write your CRUD methods, but I found it nice to be able to control exactly what you want those doing.

For starters, let's define our model.  In this case, we basically define our table structure in relatively broad strokes.

Simple enough.  Remember, you still need to write the actual SQL to create these tables with play evolutions.

Next, let's take a look at one of our DAOs.

We define our column methods, and a * projection that acts how would expect it would with SQL.  Next, we create a class that sets up the dbConfig, our query object (exerciseTypes), a method to map ids to names for option dropdowns, and our insert and list methods.  Fairly simple.

Per TDD, here is a small test that makes sure we can insert and retrieve things:

Nothing out of the ordinary here either.

So, this concludes things for now.  I've got a ways to go on my scala skills, and this app certainly has a bit to go as well.  I'm hoping to document the app's progress and post any "gotchas" I run into from here on out as well.

Next time, I'll try to demonstrate how to add a datatable for quick CRUD and sorting (Part 2: http://stonecolddev.in/posts/playing-with-scala-building-a-small-web-app-with-play-2-4-play-slick-and-postgres-part-2-testing)


Sign in to reply

Replies:

Thanks for the great write up! I am setting up a webapp very similar to yours and was going through this version/documentation mismatch hell. You saved me a lot of time!

Reply

  • Hey, thanks for the reply! Sorry for getting back to you so late, I don't have email notifications set up on here yet. I'm glad I could be of help. I'm hoping to finally get part three out this week some time as well, in case you're interested in following along.

    Reply

Hi Devin,

I had a look at your build.sbt (here https://github.com/dhoss/steel/blob/master/build.sbt), and there are a couple of things you should change. First, remove the dependency to jdbc module. You are using the play-slick module for all database accesses, so you should not need to Play jdbc. In fact, as soon as you update to play-slick 1.0.0-RC2 (which was released last week, together with Play 2.4.0-RC3), you will get an exception similar to https://playframework.com/documentation/2.4.0-RC3/PlaySlickFAQ#A-binding-to-play.api.db.DBApi-was-already-configured. Second, update to play-slick 1.0.0-RC2 because RC1 had an annoying issue (https://github.com/playframework/play-slick/issues/245) that could prevent starting your app.

Otherwise, it's a good article. I'll see how I can clarify why you need both

slick.dbs.default.driver="slick.driver.PostgresDriver$"  slick.dbs.default.db.driver="org.postgresql.Driver"

in your application.conf. But, in a nutshell, the first is the Slick driver (which you will be using in your code), while the second is the JDBC driver which is going to be used by Slick backend. See the Slick documentation for DatabaseConfig http://slick.typesafe.com/doc/3.0.0/database.html#databaseconfig

Thanks for trying it out, and taking the time to write about your experience.

Reply

  • i am having the same problem

    rovisionException: Unable to provision, see the following errors: 1) No implementation for play.api.db.slick.DatabaseConfigProvider was bound. while locating play.api.db.slick.DatabaseConfigProvider for parameter 0 at repo.StudentRepo.<init>(StudentRepo.scala:17) while locating repo.StudentRepo for parameter 0 at controllers.LoginController.<init>(LoginController.scala:24) while locating controllers.LoginController for parameter 6 at router.Routes.<init>(Routes.scala:47) while locating router.Routes while locating play.api.inject.RoutesProvider while locating play.api.routing.Router for parameter 0 at play.api.http.JavaCompatibleHttpRequestHandler.<init>(HttpRequestHandler.scala:200) while locating play.api.http.JavaCompatibleHttpRequestHandler while locating play.api.http.HttpRequestHandler

    my build.sbt

     

    name := """demo"""

    version := "1.0-SNAPSHOT"

    lazy val root = (project in file(".")).enablePlugins(PlayScala)

    scalaVersion := "2.11.7"

    libraryDependencies ++= Seq(
    cache,
    ws,
    specs2 % Test,
    "org.webjars" %% "webjars-play" % "2.5.0-1",
    "org.webjars" % "bootstrap" % "3.1.1-2",
    "com.adrianhurt" %% "play-bootstrap" % "1.0-P25-B3",
    "com.typesafe.play" %% "play-slick" % "1.1.1",
    "com.h2database" % "h2" % "1.4.187" ,
    "org.postgresql" % "postgresql" % "9.4-1206-jdbc4",
    "com.adrianhurt" %% "play-bootstrap" % "1.0-P25-B3",
    "ch.qos.logback" % "logback-classic" % "1.1.3",
    "com.typesafe.play" %% "play-slick-evolutions" % "1.1.1",
    "com.typesafe.slick" %% "slick-hikaricp" % "3.1.1",
    "com.typesafe.slick" %% "slick" % "3.1.1",
    "org.seleniumhq.selenium" % "selenium-server" % "2.52.0",
    "org.seleniumhq.selenium" % "selenium-firefox-driver" % "2.52.0",
    "org.scalatest" %% "scalatest" % "2.2.1" % "test",
    "org.scalatestplus" %% "play" % "1.4.0-M3" % "test",
    "org.seleniumhq.selenium" % "selenium-htmlunit-driver" % "2.52.0"

    )
    javaOptions in Test += "-Dconfig.file=conf/test.conf"

    coverageExcludedPackages :="<empty>;router\\..*;"

    resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases"

    // Play provides two styles of routers, one expects its actions to be injected, the
    // other, legacy style, accesses its actions statically.
    routesGenerator := InjectedRoutesGenerator


    resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/"



     

    Reply

  • Wow! My first comments on this blog.  Thanks for taking the time to check this out.  

    I'll be sure to make the changes you mentioned, and update the article as well.

     

    Again, much appreciation for setting me straight, I've got lots more to write about in the coming weeks.

    Reply

By the way, Slick is a FRM (http://slick.typesafe.com/doc/3.0.0/introduction.html#functional-relational-mapping), not a ORM.

Reply

  • Thanks! I was actually searching for what to call it but fell short. I'll update the article with that as well.

    Reply