DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report

Migrating to Play 2 and My ÜberConf Presentation

Matt Raible user avatar by
Matt Raible
·
Jul. 03, 12 · Interview
Like (0)
Save
Tweet
Share
2.65K Views

Join the DZone community and get the full member experience.

Join For Free
in my last post about migrating to play 2, i said i'd write another post on the rest of my experience. while i'm not completely finished with migrating to play 2, i feel like i've done enough to talk about the issues i encountered.

validation and displaying errors
with play 1, i can't help but think validation was a bit more intuitive. for example, here's how i populated an object from request parameters, converted a value and validated its data was fit to put in a database.

var workout = params.get("workout", classof[workout])

// change duration to time
var duration = params.get("workout.duration")
workout.duration = convertwatchtotime(duration)

validation.valid("workout", workout)

if (validation.haserrors) {
  renderargs.put("template", "profile/edit")
  edit(id);
  ...
} else { // put into db

with play scala 2, you have to define a form structure and bind it from the request. based on what i was able to conjure up, i ended up writing the following code to accomplish the same thing:

val workoutform = form(
  mapping(
    "id" -> ignored(notassigned: anorm.pk[long]),
    "title" -> text,
    "description" -> text,
    "duration" -> nonemptytext,
    "distance" -> nonemptytext,
    "postedat" -> optional(date),
    "athleteid" -> optional(longnumber)
  )((id, title, description, duration, distance, postedat, athleteid) =>
    workout(id, title, description, convertwatchtotime(duration), distance.todouble, null, 0))
    ((w: workout) =>
      some((w.id, w.title, w.description, w.duration.tostring, w.distance.tostring, null, some(0))))
)
...
workoutform.bindfromrequest.fold(
  form => {
    ok(scalate("/profile/edit.jade").render(request, 'errors -> form.errors))
  },
  workout => { // put into db

first of all, the play 2 version is quite a bit more verbose, but most of that comes from the re-defining of my model object as a form. it seems strange that the java api allows you to do it in one line whereas the scala version does not. also, i was unable to figure out how to get the data from my "form" back into the request so i could refill input fields. i'll admit, i didn't spend a lot of time trying to figure it out, but it did fail the 10 minute test. note to self: use html5's required attribute to reduce the need for server-side validation on modern browsers.

on a more positive note, i did like the way i was able to use routes in my jade templates. it was as simple as importing the routes class and using it as you would in play's scala templates:

-import controllers._

form(method="post" class="form-stacked" id="workoutform"
  action={routes.profile.postworkout(workout.map(_.id.get))})
  input(type="hidden" name="id" value="#{workout.map(_.id)}")

secure social
after getting most of my ui working, i started looking at the secure social module for play 2 . below are the steps i had to go through to install it:

  1. cloned github project to my hard drive.
  2. copied module-code/* into my projects' modules/securesocial directory.
  3. modified project/build.scala to add securesocial and dependson to my project.
    val securesocial = playproject(
      appname + "-securesocial", appversion, mainlang = scala, path = file("modules/securesocial")
    )
    
    val main = playproject(appname, appversion, appdependencies, mainlang = scala).settings(
      // add your own project settings here
    ).dependson(securesocial).aggregate(securesocial)
    
  4. added a conf/securesocial.conf and included it in my application.conf with the following line:
    include "securesocial.conf"
    
  5. added a conf/play.plugins with the following to get twitter to load as a provider:
    10000:securesocial.core.providers.twitterprovider
    
  6. created an inmemoryuserservice.scala and referenced it in my play.plugins file:
    9999:services.inmemoryuserservice
    
  7. added secure social's routes to my conf/routes file.

once i'd finished all these steps, i fired up my app and was pleasantly surprised to find i could navigate to /login and successfully authenticate via twitter. installing secure social in a play 2 app is quite a bit harder than adding it as a dependency in play 1, but i was thankful that i got it to work in under 10 minutes.

heroku
the next thing i did was attempt to deploy my app to heroku. i knew there might be some issues with scalate after reading jan helwich's blog post about scalate on heroku. the first things i encountered were 1) a successful startup and 2) an error in my browser.

action not found

i was able to reproduce this issue locally by running "play clean stage" and starting the app with "target/start". after 30 minutes of banging my head against the wall, i guessed it might be caused by secure social. removing secure social solved the problem and i was back in business. however, this time when i deployed, i received the error that jan had mentioned might happen.

2012-06-21t07:07:12+00:00 app[web.1]: [error] o.f.s.l.defaultlayoutstrategy - unhandled: org.fusesource.scalate.templateexception: target/../tmp/src/app/target/../app/views/layouts/default.jade.scala (no such file or directory)
2012-06-21t07:07:12+00:00 app[web.1]: [error] application - 
2012-06-21t07:07:12+00:00 app[web.1]: 
2012-06-21t07:07:12+00:00 app[web.1]: ! @6amfgf02h - internal server error, for request [get /] ->
2012-06-21t07:07:12+00:00 app[web.1]: 
2012-06-21t07:07:12+00:00 app[web.1]: play.core.actioninvoker$$anonfun$receive$1$$anon$1: execution exception [[templateexception: target/../tmp/src/app/target/../app/views/layouts/default.jade.scala (no such file or directory)]]
2012-06-21t07:07:12+00:00 app[web.1]:   at play.core.actioninvoker$$anonfun$receive$1.apply(invoker.scala:134) [play_2.9.1-2.0.1.jar:2.0.1]
2012-06-21t07:07:12+00:00 app[web.1]:   at play.core.actioninvoker$$anonfun$receive$1.apply(invoker.scala:115) [play_2.9.1-2.0.1.jar:2.0.1]
2012-06-21t07:07:12+00:00 app[web.1]:   at akka.actor.actor$class.apply(actor.scala:311) [akka-actor-2.0.1.jar:2.0.1]
2012-06-21t07:07:12+00:00 app[web.1]:   at play.core.actioninvoker.apply(invoker.scala:113) [play_2.9.1-2.0.1.jar:2.0.1]
2012-06-21t07:07:12+00:00 app[web.1]:   at akka.actor.actorcell.invoke(actorcell.scala:619) [akka-actor-2.0.1.jar:2.0.1]
2012-06-21t07:07:12+00:00 app[web.1]:   at akka.dispatch.mailbox.processmailbox(mailbox.scala:196) [akka-actor-2.0.1.jar:2.0.1]
2012-06-21t07:07:12+00:00 app[web.1]: caused by: org.fusesource.scalate.templateexception: target/../tmp/src/app/target/../app/views/layouts/default.jade.scala (no such file or directory)
2012-06-21t07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.templateengine.compileandload(templateengine.scala:834) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21t07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.templateengine.compileandloadentry(templateengine.scala:691) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21t07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.templateengine.liftedtree1$1(templateengine.scala:411) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21t07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.templateengine.load(templateengine.scala:405) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21t07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.templateengine.load(templateengine.scala:475) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21t07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.layout.defaultlayoutstrategy.org$fusesource$scalate$layout$defaultlayoutstrategy$$trylayout(defaultlayoutstrategy.scala:77) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21t07:07:12+00:00 app[web.1]: caused by: java.io.filenotfoundexception: target/../tmp/src/app/target/../app/views/layouts/default.jade.scala (no such file or directory)
2012-06-21t07:07:12+00:00 app[web.1]:   at java.io.fileoutputstream.open(native method) ~[na:1.6.0_20]
2012-06-21t07:07:12+00:00 app[web.1]:   at java.io.fileoutputstream.<init>(fileoutputstream.java:209) ~[na:1.6.0_20]
2012-06-21t07:07:12+00:00 app[web.1]:   at java.io.fileoutputstream.<init>(fileoutputstream.java:160) ~[na:1.6.0_20]
2012-06-21t07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.util.ioutil$.writebinaryfile(ioutil.scala:111) ~[scalate-util-1.5.3.jar:1.5.3]
2012-06-21t07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.templateengine.compileandload(templateengine.scala:747) ~[scalate-core-1.5.3.jar:1.5.3]
2012-06-21t07:07:12+00:00 app[web.1]:   at org.fusesource.scalate.templateengine.compileandloadentry(templateengine.scala:691) ~[scalate-core-1.5.3.jar:1.5.3]
</init></init>

i tried his suggestion (removing the first slash on my scalate paths) but it didn't work. i tried adding in scalate pre-compilation, but that didn't solve the problem either. the good news is i did solve it this afternoon by changing my scalate object to use a canonical path instead of an absolute one.

iphone app
in addition to the changes mentioned here, i re-wrote the iphone app for play more. i upgraded it to phonegap 1.8.1 , used jqtouch , developed with appcode (instead of xcode) and had a pretty good experience. the only issue i ran into was with the jqt.bars extension from datazombies . i briefly tried to integrate it and then decided not to. however, i left all its js and css in my page and this caused scrolling to not work and made the app sluggish. removing the files solved the problem. the other big improvement i made was moving all the static assets (js, css, images) into the mobile app instead of referencing them from http://play-more.com. this reduced the startup time from 30-40 seconds to 3-4 seconds!

presentation and source code
i presented all of these findings and told my story at überconf this morning. in addition, i announced that the code is now open source and available on github . you can view my presentation below or on slideshare .

conclusion
would i do it again? learning scala was my primary motivator for digging into play. when play 2 was announced, i thought migrating my app to the new version would be easy. unfortunately, the play developers decided to break backwards-compatibility and wrote a whole new framework that still seems to be in its infancy. i think you can see from my last couple of posts that migrating from play 1.x to 2.x was not an easy task. it's been nice to learn more about play and scala in the process, but living on the bleeding edge was also quite frustrating at times. play scala 1.x seemed to be quite a bit more productive than play 2, especially because of the magic[t] in anorm, but also because it required less code in controllers.

i found anorm and scalate to be huge time sinks and don't know if i'd recommend using either one in a play 2 project. i'm sure scalate will be easier to use as its play 2 integration gets more refined, but i don't know if there's any hope for a jdbc abstraction that doesn't produce error messages when things go south.

on the upside, my experience with html5 and coffeescript was wonderful. they did what i asked them to do and didn't cause much pain. when a browser-based webapp couldn't handle geo running in the background, phonegap came to the rescue.

mobile app

Published at DZone with permission of Matt Raible, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Microservices Testing
  • Introduction To OpenSSH
  • Testing Level Dynamics: Achieving Confidence From Testing
  • The 5 Books You Absolutely Must Read as an Engineering Manager

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: