Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
August 24, 2013 02:32 am GMT

Building Ribbit in Scala

In this tutorial we will implement the Ribbit application in Scala. We’ll be covering how to install the Play web framework, a NetBeans plugin for it, and finally the code in Scala. If you are new to Scala, check out this previous tutorial which will help you set up your environment and provides you with a general platform that you can build upon.

Even though the essence of Ribbit is to create/send/read Ribbits (our version of tweets), we will spend a large part of this tutorial explaining how Play works, authentication, and persistence. After these are in place, the rest becomes much easier. We will also implement ribbit creation, submission and listing out all ribbits. Following someone, advanced user settings, and direct messages will be an extra assignment for you to complete on your own. I am sure if you manage to follow along with this tutorial and create Ribbit as explained below, these three functionalities will be easily accomplished as homework.


Download and Install Play

There are quite a few web frameworks for Scala. Some are purely functional and a few are somewhat MVC-ish. I’ve chosen Play for this example because it resembles an MVC architecture and it should be more familiar to people used to these kinds of frameworks. Additionally, it is one of the best and most recommended web frameworks for Scala.

So, go ahead and download Play for Scala. Please note this tutorial was written when the latest stable version was 2.1.1, you may need to adapt the content below for newer versions.

Installing Play is as simple as extracting the archive into a folder with both read and write permissions and then adding the path to the “play” executable to your PATH. At the time of writing this article, the only requirement for Play is Java 6.


Installing the Play Plugin for NetBeans

There is a very nice plugin for NetBeans which will make your life easier while working with Play. It allows you to create and manage Play projects directly from NetBeans. Go ahead and download the Play plugin for NetBeans from the official plugin page. After you have the .nbm file downloaded, just add it to NetBeans using its plugin manager.

Next, you’ll need to specify the path to the “play” executable for your NetBeans plugin. Go to Tools / Options / Miscellaneous / Play. Browse to where you extracted Play’s archive, until you can find the executable itself. Here’s what it looked like for me:

NetBeansPlayHomeSettings

Creating the Project

In NetBeans select File / New Project and choose Play / Simple Scala Application.

NetBeansNewPlayScalaApplication

Then specify the folder you want your project to reside in. NetBeans will generate basic settings and a directory structure for you.

NetBeansInitialPlayProject

Configuration for Building the Project

Before you can run your project, you have to make sure the correct SBT version is being used. By default version 0.11.3 is required, but I have 0.12.2 installed. You may have another version. So switch to the “Files” view in NetBeans and locate the Play project you created. If you are not using NetBeans just use your favorite file manager to find the project’s folder. You will find there, in the “project” subfolder a file called "build.properties". Edit it and change the sbt.version to the correct value. If you don’t have SBT installed, please review the tutorial I mentioned in the introduction to this article. It explains all the details on how to install SBT.

If you have recently updated SBT, don’t forget to republish the NetBeans SBT plugin locally. Go to your “nbsbt” folder and run these commands:

rm -r ~/.ivy2/local/org.netbeans.nbsbtsbt clean compile publish-local

This will also solve any errors telling you that SBT can’t find the NetBeans plugin or that an incompatible binary type was detected.

However, Play has a little bug, and can not use the user’s ~/.ivy2 repository. Instead, it uses its own local repositories. There are several workarounds that you can find on the Internet, the easiest one I’ve found, is to just create a symbolic link in Play’s folder / repository/local that points to ~/ivy2/local/org.netbeans.nbsbt.

In the same directory, in the plugins.sbt file, make sure the proper Play version is set at this line:

// Use the Play sbt plugin for Play projectsaddSbtPlugin("play" % "sbt-plugin" % "2.1.1")

Finally, in the same directory, in the file called Build.scala, make sure the application’s name has no white spaces. If you specified your project with white spaces in its name, this will be wrongly set.

val appName         = "RibbitInScala"

Afterwards, you should be able to right click on the Ribbit in Scala project in the “Projects” view and successfully execute “Build”. Building the project for the first time will take a little while to complete. You should see the progress in an SBT window in NetBeans. Subsequent builds should take only a few seconds.

Finally, we can run our project. Just right click on it and select “Run”. In NetBeans’ output window, you will see instructions on how to access your project. If all goes well, these should be the last lines in that log:

[info] Done updating.--- (Running the application from SBT, auto-reloading is enabled) ---[info] play - Listening for HTTP on /0:0:0:0:0:0:0:0:9000(Server started, use Ctrl+D to stop and go back to the console...)

We can now see our application running on localhost’s port 9000.

PlayWelcome

This is the default Play welcome screen. It is like this because we have not yet implemented any actual application code. If you see this, you are up and running and ready for the next section. Congratulations.


Basic Play Configuration

Play is very similar to other MVC web frameworks, so I won’t go into great detail about its inner workings. In this section, let’s just create a simple “Hello World” view and controller, which will be shown using a default route, so that we can get accustomed with Play’s architecture.

In the Configuration/routes file, you can see that every call to the root (/) is redirected to the Application controller.

GET/controllers.Application.index

In controllers, you will find Application.scala. The code in this file will render the "index" template from views.

def index = Action {    Ok(views.html.index("Your new application is ready."))  }

In the views folder, there are a couple of files: index.scala.html and main.scala.html. The first one will call the second one to show you the content. In the second one, there is an HTML structure, CSS inclusions, JavaScript library inclusions and a few other things. Feel free to play around with these files, but explaining the content in them is however not the concern of this article.

In Application.scala change the parameter being passed into index() to "Hello World".

Ok(views.html.index("Hello World"))

Then modify index.scala.html to display it.

@(message: String)@main("Our first content") {<p>@message</p>}

The first line in a template file is the function signature. (message: String) means this view is getting a single parameter called "message" of the type String. Then comes @main, a function that returns a paragraph HTML tag with the message contained inside of it. But for all of this to work we need main.scala.html also. This has a different signature. The first parameter which is the title (check your browser’s tab / title) and the other one is the content. "Our first content" will be the title and the return value of main will be the content.

@(title: String)(content: Html)

title is a String and content must be HTML. The rest of the main.scala.html file is self-explanatory. After a refresh in your browser, you will see “Hello World” instead of the previous documentation and welcome screen.

If you want to learn more about Play’s inner workings check out the official documentation.


Creating the Home Page and Login Screen

As usual with these Ribbit tutorials, we will work with the following resources introduced in “The Design” article. So, go ahead and download the layout.zip file and extract it. We will refer to this folder as "LAYOUT_HOME".

Getting the Files

We need less.js in our Play project, so copy it from LAYOUT_HOME into our project’s "public/javascripts" folder. Then copy style.less from LAYOUT_HOME to our project’s "public/Stylesheets" folder. Continue with copying LAYOUT_HOME/gfx/frog.jpg, logo-nettuts.png and logo.png to our project’s "public/images" folder.

Preparing the Views

At this point we don’t care about authentication and form generation. We will just take and adapt the HTML code from LAYOUT_HOME/home.html so that we have something visual to work with.

The HTML skeleton of our Ribbit app will reside in the view called main.scala.html. You actually already have this view generated, as we’ve seen it in the previous section, now just modify it like so:

@(title: String)(content: Html)<!DOCTYPE html><html>    <head>        <title>@title</title>        <link rel="stylesheet" media="screen" href='@routes.Assets.at("stylesheets/main.css")'><link rel="stylesheet/less"  media="screen" href='@routes.Assets.at("stylesheets/style.less")'>        <link rel="shortcut icon" type="image/png" href='@routes.Assets.at("images/favicon.png")'>        <script src='@routes.Assets.at("javascripts/jquery-1.7.1.min.js")' type="text/javascript"></script>        <script src='@routes.Assets.at("javascripts/less.js")' type="text/javascript"></script>    </head>    <body><header><div class="wrapper"><img src='@routes.Assets.at("images/logo.png")'><span>Twitter Clone</span><form><input name="email" type="text"><input name="password" type="password"></form></div></header>        @content<footer><div class="wrapper">Ribbit - A Twitter Clone Tutorial<img src='@routes.Assets.at("images/logo-nettuts.png")'></div></footer>    </body></html>

As you can see the code now references the "style.less" file we introduced and the "less.js" JavaScript and all paths to images were also updated to use Play’s '@routes.Assets.at(...)' syntax. To avoid confusing the editors with double quotes inside double quoted HTML tags, I’ve chosen to single quote the HTML tags that are using Play variables or methods.

The next file we need to update is our index.scala.html view. This is the index file providing the content for the main page. What we return from this will be inserted into main.scala.html at the line where "@content" is specified.

@(message: String)@main("Ribbit in Scala & Play") {<div id="content"><div class="wrapper"><img src='@routes.Assets.at("images/frog.jpg")'><div class="panel right"><h1>New to Ribbit?</h1><p><form><input name="email" type="text"><input name="password" type="text"><input name="password2" type="password"><input type="submit" value="Create Account"></form></div></div></div>}

In this case we just changed the title that is passed to main and returned plain old HTML code.

Now, if you run your project and access https://localhost:9000 you should see an almost working home page for Ribbit.

RibbitFirstAttempt

It’s not yet perfect, but we have styled forms and all images are correctly referenced.

Correcting the Stylesheets

Now we have to check and update our style.less file to use the backgrounds and other things from our image directory. Of course, the first thing will be to copy the rest of the files from LAYOUT_HOME/gfx to our project’s "public/images" folder.

Play with Scala, supports LESS right out of the box. To use this feature we first need to drop less.js from our views and transform our style.less stylesheet into a Play asset. Start by just deleting the following line from main.scala.html:

<script src='@routes.Assets.at("javascripts/less.js")' type="text/javascript"></script>

Now, if you refresh your project’s page in the browser, it will look ugly and unstyled.

RibbitUnstyled

Then move "style.less" from the project’s "public/Stylesheets" folder into the "app/assets/stylesheets" folder. Create it, if needed. Rename "style.less" into "main.less". Play will automatically compile it into "public/Stylesheets/main.css" and we can delete the reference to "style.less" from main.scala.html.

Refresh your browser window again and make sure nothing is cached. You may need to stop and run your Play project again for the effects to take place. If all goes well, you should see a page similar to how it looked like initially. There may be some slight differences, but don’t worry, we will fix them in a minute.

Here is how the "head" part of your main.scala.html file should look like now.

<head><title>@title</title><link rel="stylesheet" media="screen" href='@routes.Assets.at("stylesheets/main.css")'><link rel="shortcut icon" type="image/png" href='@routes.Assets.at("images/favicon.png")'><script src='@routes.Assets.at("javascripts/jquery-1.7.1.min.js")' type="text/javascript"></script></head>

Finally, edit "main.less" and replace all "gfx/" folder specifications for images with "/assets/images/". You may need to fix a couple widths and heights also, because the less file may be compiled differently than the JavaScript version. Afterwards, here is what we end up with:

RibbitIndexStyled

User Management

Play’s Built-in Authentication Functions

For our example, we will simply use Play’s built-in authentication mechanisms. These are pretty good and quite complex, so we will only take what is absolutely needed for us. In Application.scala we will define a form and some actions for authentication.

package controllersimport play.api._import play.api.mvc._import play.api.data._import play.api.data.Forms._import models._import views._object Application extends Controller {val loginForm = Form(tuple("email" -> text,"password" -> text) verifying ("Invalid email or password", result => result match {case (email, password) => check(email, password)}))def check(username: String, password: String) = {(username == "[email protected]" && password == "123")}def index = Action { implicit request =>Ok(html.index(loginForm))}def authenticate = Action { implicit request =>loginForm.bindFromRequest.fold(formWithErrors => BadRequest(html.index(formWithErrors)),user => Redirect(routes.Application.public).withSession("email" -> user._1))}def logout = Action {Redirect(routes.Application.index).withNewSession.flashing("success" -> "You've been logged out")}def public = Action { implicit request =>Ok(html.public("Logged in")("John Doe"))}}

loginForm is a value we will use to authenticate our user. This form will be used in the index.scala.html view and it will call the authenticate action on our controller (we will study the view in a moment). The validation on the form will kick in and the pattern match will force a call to the "check" method. For the time being, check only returns a true or false value for the hard-coded user, [email protected] and password 123.

The index function renders the index view with the loginForm sent in as parameter. We need this to be shown on our home page.

The authenticate function binds to the form: if there are any errors, it goes back to the index page or if it was successful, it will render a view called "public" with the session for that view, populated with the user’s email. This is a very important step because if you omit the ".withSession" call, even though your user is authenticated, you will have no way of knowing which user was logged in.

Finally, logout clears up the session while the public function renders the public view, at this point with just the hard-coded user name “John Doe”.

Update Routes

In the previous section we created several new actions for our controller. We now have to update our routes to accommodate these new actions:

# Routes# This file defines all application routes (Higher priority routes first)# ~~~~# Home pageGET     /                           controllers.Application.index# AuthenticationPOST    /login                      controllers.Application.authenticateGET     /logout                     controllers.Application.logout# MessageGET     /publiccontrollers.Application.public# Map static resources from the /public folder to the /assets URL pathGET     /assets/*file               controllers.Assets.at(path="/public", file)

We added definitions for login, logout, public and of course for the authenticate action called from the form. This is enough for the time being.

Add the Login Form to the Header

We now have a controller and route actions, next we’ll update our views. The first one to take care of is main.scala.html. We will have to update the “header” part so that it will display a form, from the controller, instead of the two built-in inputs.

<header><div class="wrapper"><img src='@routes.Assets.at("images/logo.png")'><span>Twitter Clone</span>@loginForm</div></header>

@loginForm has to be specified as a parameter, so the first line of the file becomes:

@(title: String)(loginForm: Html)(content: Html)

Now we will build the form’s content in the index.scala.html view and pass it to main.

@(form: Form[(String,String)])(implicit flash: Flash)@main("Welcome to Ribbit in Scala") {@helper.form(routes.Application.authenticate) {<input type="email" name="email" placeholder="Email" id="email" value='@form("email").value'><input type="password" name="password" id="password" placeholder="Password">}} {<div id="content"><div class="wrapper"><img src='@routes.Assets.at("images/frog.jpg")'><div class="panel right"><h1>New to Ribbit?</h1><p><form><input name="email" type="text"><input name="password" type="text"><input name="password2" type="password"><input type="submit" value="Create Account"></form></div></div></div>}

One important piece of code in this view is: @helper.form(routes.Application.authenticate). This is how we call authenticate on our Application controller from the form.

Create a Public View

Finally, create the public.scala.html view so we have a destination to redirect to in case of a successful login. This will be mostly empty at this point.

@(title: String)(user: String)@main("Public Tweets") {<a id='btnLogOut' href="@routes.Application.logout" class="logout">logout</a>} {<div>@user</div>}

Getting a Slick Database Backend

Scala database backends are very cool, because they provide a syntax which hides SQL or other data languages and they map their functionality directly as Scala classes. You may think of them like ORM libraries, but implemented in a much more optimal way. Our database backend of choice is called Slick. Installing it will be as simple as adding it as a dependency in our build.scala.

"com.typesafe.slick" %% "slick" % "1.0.1","com.h2database" % "h2" % "1.3.166"

The first line is the Slick library, while H2 is the database that we will use. H2 is the equivalent of MySQL or Postgres or whatever your favorite database server may be. Of course, these lines go into the appDependencies definition.

val appDependencies = Seq("org.mindrot" % "jbcrypt" % "0.3m","com.typesafe.slick" %% "slick" % "1.0.1","com.h2database" % "h2" % "1.3.166")

Accounts, Databases and Authentication

Managing Accounts With a Model

It’s now time to make our application actually do some kind of authentication. We will introduce a model called Account. Create a file called Account.scala in your source packages / models folder. You may have to create the models folder if it’s missing.

The Account model will be responsible for user management. It will connect to the database and find our John Doe user, authenticate him, and provide other useful search methods for us. Here’s what our model looks like:

package modelsimport org.mindrot.jbcrypt.BCryptimport scala.slick.driver.H2Driver.simple._import Database.threadLocalSessioncase class Account(id: Int, email: String, password: String, name: String)object Account {object Users extends Table[(Int, String, String, String)]("USERS"){def id = column[Int]("ID", O.PrimaryKey)def email = column[String]("EMAIL")def password = column[String]("PASSWORD")def name = column[String]("NAME")def * = id ~ email ~ password ~ name}def authenticate(email: String, password: String): Option[Account] = {findByEmail(email).filter { account => BCrypt.checkpw(password, account.password) }}def findByEmail(email: String): Option[Account] = findBy("email", email)def findById(id: Int): Option[Account] = findBy("id", id.toString)def findAll(): Seq[Account] = findById(1).toSeqdef findBy(field: String, value: String): Option[Account] = {val user = Database.forURL("jdbc:h2:mem:users", driver = "org.h2.Driver") withSession {Users.ddl.createUsers.insert(1, "[email protected]", BCrypt.hashpw("123", BCrypt.gensalt()), "John Doe")val foundUsers = field match {case "email" => for {u <- Users if u.email.toLowerCase === value.toLowerCase} yield(u)case "id" => for {u <- Users if u.id === value.toInt} yield(u)}foundUsers.firstOption}user map {case (id, email, password, name) => new Account(id, email, password, name)}}}class NullAccount(id: Int = -1, email: String = "not@set", password: String = "", name: String = "Unknown")extends Account(id: Int, email: String, password: String, name: String)  {}

Well, it’s pretty long, allow me to explain it line-by-line.

  • Line 1 – the package for this file has to be “models”
  • Lines 3-5 – import encryption, database driver and session libraries
  • Lines 7-8 – we define a class Account and an object for it with constructor parameters
  • Lines 11-15 – we define a User object that extends Table. This is a link between Scala and our database. In it, we have all the parameters that characterize a user.
  • Lines 20-22 – define a function called "authenticate". This will be called from the Application controller’s form instead of “check”. It will return an optional Account object. It may return None if the user is not found or the authentication fails. The logic in this class calls another method defined below which returns an Account for an email and then checks if the account’s password matches what we typed in the form. At this point we also introduced encryption for the password.
  • Lines 24-26 – two functions for finding a user by email and by id. We may not need the findById but I’ve put it in here for exemplification.
  • Line 28 – will find all of the users. At this point though, it is not yet implemented, we just return a user with id 1 as a sequence.
  • Lines 30-49 – is where most of our logic is contained. findBy is a method that connects to an H2 database residing in memory. This is a temporary DB and we will just insert John Doe into it. File persistence will come a little later. Next, the findBy method finds all of the users from the DB, based on ID or email, depending on the parameter specified. Finally, it returns an Option[Account].
  • Lines 53-55 – we define a null version of Account. Just in case we end up on the public page with an unknown, but authenticated user, we don’t want our view to break.

Connecting the Application Controller to Accounts

Now that Account can authenticate our user, we can get rid of the "check" function in the Application controller and change our form into this:

val loginForm = Form(tuple("email" -> text,"password" -> text) verifying ("Invalid email or password", result => result match {case (email, password) => Account.authenticate(email, password).isDefined}))

Instead of calling check we will call Account.authenticate and check if the returned value is defined, as in the case of a failure, it can return None.

def public = Action { implicit request =>def getLoggedInEmail = request.session.get("email") match {case Some(email) => emailcase None => ""}def getUserFromOption(user: Option[Account]) = user match {case Some(account) => accountcase None => new NullAccount}val user = getUserFromOption(Account.findByEmail(getLoggedInEmail))Ok(html.public("Logged in")(user))}

The public function has to be updated as well to get a user account by the email address, kept in the session.

Update the View

The public.scala.html view has to be updated in order to get a parameter of type Account and be able to obtain all user information from it.

@(title: String)(user: Account)@main("Public Tweets") {<a id='btnLogOut' href="@routes.Application.logout" class="logout">logout</a>} {<div>@user.name</div>}

Here, we just output user’s name at this point.

AuthJohnDoe

Creating Users and Using Real Persistence for Them

Now that we have authentication with our database working, it’s time to make the database persistent. It is also a good time to implement user creation. We will again be forced to rethink parts of our actual design. In previous sections we started our reasoning and development with the business logic (the code in Applications.scala and in Account.scala) and worked our way up to the views. I propose we take a reverse approach this time, so that you can see an example where we start with index.scala.html, our view, and develop step by step toward the functionality that we want, ending with Account.scala.

Writing a Play Form for Account Creation

We have to modify index.scala.html so that our second form, for the user creation, will also be created using Play’s helpers, so that this code:

<p><form><input name="email" type="text"><input name="password" type="text"><input name="password2" type="password"><input type="submit" value="Create Account"></form>

Becomes this, instead:

@helper.form(routes.Application.createAccount) {<input type="text" name="name" placeholder="Full Name" id="name" value='@createForm("name").value'><input type="email" name="email" placeholder="Email" id="email" value='@createForm("email").value'><input type="password" name="password" id="password" placeholder="Password"><input type="password" name="confirm" id="password2" placeholder="Confirm Password"><input type="submit" value="Create Account">}

In this code, there are two essential pieces:

  1. @createForm("...").value – which is a form that we will send in from the controller. This also requires us to change the signature of our view (see below).
  2. routes.Application.createAccount – which is the action that we will create in our controller. This requires us to update our routes and of course the Application controller.

The view’s signature becomes:

@(loginForm: Form[(String,String)], createForm: Form[(String, String, String, String)])(implicit flash: Flash)

As you can see, we are now always getting two forms. To better differentiate them, we also updated the name of the previous variable to "loginForm", so we have to update the input for login as well.

<input type="email" name="email" placeholder="Email" id="email" value='@loginForm("email").value'>

We also had to update main.less to accommodate the extra input, but these small marginal adjustments here-and-there are not that relevant.

RibbitLoginWithNewCreateForm

Adding the New Route

This is easy, just one more line in the "routes" file.

# User CreationPOST /createcontrollers.Application.createAccount

Adding in New Controller Functionality

First, add a new form for creating a user:

val createForm = Form(tuple("name" -> text,"email" -> text,"password" -> text,"confirm" -> text) verifying ("Invalid email or password", result => result match {case (name, email, password, confirm) => Account.create(name, email, password, confirm).isDefined}))

This is where we define the four fields that we’ll need. Then in the case where we call Account.create(...).isDefined, this will force us to write a "create" function in our Account model.

Next, we need to define the "createAccount" action:

def createAccount = Action { implicit request =>createForm.bindFromRequest.fold(formWithErrors => BadRequest(html.index(loginForm,formWithErrors)),user => Redirect(routes.Application.public).withSession("email" -> user._2))}

For this action, on failure, we will redirect to the index page and send in the loginForm plus our formWithErrors. This will help keep the user’s filled in form data present, after a form submission. On success, we will just go to the “public” page, as we do when the authentication succeeds. We will also set and pass the email through the session.

Finally, we need to adjust all the other calls to the index view to take both forms as parameters:

def index = Action { implicit request =>Ok(html.index(loginForm, createForm))}def authenticate = Action { implicit request =>loginForm.bindFromRequest.fold(formWithErrors => BadRequest(html.index(formWithErrors, createForm)),user => Redirect(routes.Application.public).withSession("email" -> user._1))}

Creating the Account in the Database

Up until now, all of our code for user creation was just to support the framework: views, routes, controller actions, forms. Now it’s time for some serious business. We will need to change Account.scala quite a bit, so below is the code for the changed version and then afterwards, the explanation.

package modelsimport org.mindrot.jbcrypt.BCryptimport scala.slick.driver.H2Driver.simple._import Database.threadLocalSessioncase class Account(email: String, password: String, name: String)object Account {object User extends Table[(String, String, String)]("USERS"){def email = column[String]("EMAIL", O.PrimaryKey)def password = column[String]("PASSWORD")def name = column[String]("NAME")def * = email ~ password ~ name}def authenticate(email: String, password: String): Option[Account] = {findByEmail(email).filter { account => BCrypt.checkpw(password, account.password) }}def create(name: String, email: String, password: String, confirm: String): Option[Account] = {if (password != confirm) Noneelse {Database.forURL("jdbc:h2:users", driver = "org.h2.Driver") withSession {try {User.ddl.create} catch {case e: org.h2.jdbc.JdbcSQLException => println("Skipping table createion. It already exists.")}User.insert(email, BCrypt.hashpw(password, BCrypt.gensalt()), name)}findByEmail(email)}}def findByEmail(email: String): Option[Account] = findBy("email", email)def findByName(name: String): Option[Account] = findBy("name", name)def findAll(): Seq[Account] = findByName("John Doe").toSeqdef findBy(field: String, value: String): Option[Account] = {val user = Database.forURL("jdbc:h2:users", driver = "org.h2.Driver") withSession {val foundUser = field match {case "email" => for {u <- User if u.email.toLowerCase === value.toLowerCase} yield(u)case "name" => for {u <- User if u.name.toLowerCase === value.toLowerCase} yield(u)}foundUser.firstOption}user map {case (email, password, name) => new Account(email, password, name)}}}class NullAccount(email: String = "not@set", password: String = "", name: String = "Unknown")extends Account(email: String, password: String, name: String)  {}

Here’s what we’ve done:

  • We dropped the "id" for the user, as the email address is just as good as an id and we can use it for the unique key. This also led to changes in the Account’s signature, in NullAccount, and in the User’s signature. Users was renamed to User and now has only three fields: email, password, and name.
  • Because we removed the "id", we also changed the function "findBy". Now it can search by name and email and not by id.
  • To implement real persistence, we dropped the “mem” specification from the database connection. This makes “USERS” a real table residing in a database file called "users".
  • Finally, we added a create method to add the new user to the database. In its logic, it tries to create the table and in case it already exists, it catches the exception and just writes a nice message to the console. Check your NetBeans’ Output console, the one that opens when you select “Run” on the project. The rest of the code should be fairly obvious, insert the new user into the database and then look it up and return it with the already existing function "findByEmail".

We are done. You can now create users. Have fun with them!


Post a Ribbit

Now that we are more familiar with Play, Slick and Scala, the rest of the program is quite easy to build. We will, however, implement both posting ribbits and showing all ribbits. This is also the final state of the attached source code, so I will only mention the most interesting parts here.

To create Ribbits we have to modify our public view. As a first step, you can take the code from the layout ribbit tutorial we used at the beginning and start changing it where needed. First, we need a form generated by Play instead of the hardcoded one.

<div class="panel right"><h1>Create a Ribbit</h1><p>@helper.form(routes.Ribbits.createRibbit) {<textarea type="text" name="ribbit" placeholder="Your Ribbit here..." id="ribbit" class="ribbitText" value='@createForm("name").value' ></textarea><input type="submit" value="Ribbit!">}</p></div>

Don’t forget to update the view’s signature as well.

Then we create a new controller, called Ribbits. We can now move the "public" function here, update our Application controller and our views to call Ribbits.public instead of Application.public. We then add a "createRibbit" function in the new controller, together with our form.

package controllers[...] // many omitted importsobject Ribbits extends Controller {def createForm (session: Session) = Form(single("ribbit" -> text) verifying ("Could not add Ribbit. Sorry.", result => result match {case (ribbit) => RibbitRepository.create(ribbit, session.get("email"))._1.equals(ribbit)}))def getLoggedInUser(session: Session): Account = {def getLoggedInEmail = session.get("email") match {case Some(email) => emailcase None => ""}def getUserFromOption(user: Option[Account]): Account = user match {case Some(account) => accountcase None => new NullAccount}getUserFromOption(Account.findByEmail(getLoggedInEmail))}def public = Action { implicit request =>val user = getLoggedInUser(request.session)Ok(html.public("Logged in")(user)(createForm(request.session))(RibbitRepository.findAll))}def createRibbit = Action { implicit request =>createForm(request.session).bindFromRequest.fold(formWithErrors => BadRequest(html.public("Logged in")(getLoggedInUser(request.session))(formWithErrors)(RibbitRepository.findAll)),ribbit => Redirect(routes.Ribbits.public))}}

Then we create a new model, RibbitRepository. It will be responsible for creating and listing out all ribbits.

def create(content: String, sender: Option[String]): (String,String,String,String) = {Database.forURL("jdbc:h2:ribbits", driver = "org.h2.Driver") withSession {try {Ribbit.ddl.create} catch {case e: org.h2.jdbc.JdbcSQLException => println("Skipping table createion. It already exists.")}def senderEmail = sender match {case Some(email) => emailcase None => "[email protected]"}Ribbit.insert(content, senderEmail, new SimpleDateFormat("yyyy-MM-dd HH:mm").format(Calendar.getInstance.getTime))}findAll().last}

We also modified our database, I just called it "ribbits" and both the "Ribbits" and the "Users" are in this database. A ribbit will have some content, a sender’s email and a timestamp.


View All Ribbits

Finally, we updated our view to loop over all ribbits provided by the findAll function of the RibbitRepository model.

def findAll(): Seq[(String,String,String,String)] = {val allRibbits = Database.forURL("jdbc:h2:ribbits", driver = "org.h2.Driver") withSession {try {Ribbit.ddl.create} catch {case e: org.h2.jdbc.JdbcSQLException => println("Skipping table createion. It already exists.")}val foundRibbits = for {r <- Ribbitu <- User if u.email.toLowerCase === r.sender.toLowerCase} yield((r.content, r.sender, r.dateTime, u.name))foundRibbits.list}allRibbits}

This same method is also called on ribbit creation, so that the list is refreshed after a submission. The view simply does a map on the sequence and outputs the content.

<div id="ribbits" class="panel left"><h1>Public Ribbits</h1>@ribbits.map { ribbit =><div class="ribbitWrapper"><img class="avatar" src='@routes.Assets.at("images/user1.png")'><span class="name">@ribbit._4</span> @ribbit._2 <span class="time">@ribbit._3</span><p>@ribbit._1</p></div>}</div>

And here’s what the final version of the signature for the view should look like:

@(title: String)(user: Account)(createForm: Form[String])(ribbits: Seq[(String,String,String,String)])

Notice that we did not use "user" in the view, but we could have, so I decided to leave it in there just in case you wish to modify this code and use it however you please.

And here is the finished app in action.

RibbitFinished

Final Thoughts

So I think now is a good time to end this tutorial. Creating additional pages for the app would be very similar to the ones we have already done here, so I’ll leave this as an exercise for you. I hope I helped you to understand the basics of Scala, Play and Slick. Consider this tutorial a very basic introduction, without all of the fancy stuff like Ajax requests or auto incrementing on H2 key columns. I am sure that if you were able to follow along with this tutorial, it will provide you with a solid base that you can build on top of. Also, don’t forget to check out all of the extra information and documentation about Slick, Play and Scala that I linked to throughout this tutorial.

Thank you for reading.


Original Link: http://feedproxy.google.com/~r/nettuts/~3/1NmChMRnfGM/

Share this article:    Share on Facebook
View Full Article

TutsPlus - Code

Tuts+ is a site aimed at web developers and designers offering tutorials and articles on technologies, skills and techniques to improve how you design and build websites.

More About this Source Visit TutsPlus - Code