sudo -u grails

Grailsの記事が充実する。といいなぁ

一部で話題のIKEAorDEATHをGrailsのコントローラだけで作ってみた

http://ikeaordeath.com/ というサイト、ご存知ですか?IKEAで販売されてるアイテムとデスメタルバンドのバンド名、何がどっちかの2択を出してるサイトです。

ここを見てて、Grailsのコントローラだけでもこういう動きするページ作れそうだな、と思って作ってみました。Grailscreate-controller して、こんなコードを。

package ikeametal

class QuestionController {
  
  List ikeas = ["Vittsjö","Klubbo","Bastig","Boholmen","Grundtal","Dåtid","Samsplet","Skogaby","Adde","Nyvoll","Strandmon","Krokig","Vyssa Skont","Melltorp","Vridvinge"]
  List metals = ["Akercocke","Einherjer","Sargeist","Taake","Ensiferum","Midnattsol","Turisas","Thaurorod","Sikth","Eluveitie","Månegarm","Kovenant","Korpiklaani"]
  Random rand = new Random()
  static Integer total = 0
  static Integer correct = 0

  def index() {
    List joined = metals + ikeas
    def picked = joined[ rand.nextInt(joined.size()) ]
    render "<H1>$picked</H1> is IKEA or METAL ?" +
      g.link(action:"ikea",id:picked){"<H2>IKEA</H2>"} +
      g.link(action:"metal",id:picked){"<H2>METAL</H2>"} +
      "( $correct / $total )"
  }
  
  def metal() {
    total ++
    def ans = metals.contains(params.id) ?
      "<H1>Right!</H1> ${params.id} is Metal Band.<!--${++correct}-->" :
      "<H1>Wrong.</H1> ${params.id} is IKEA Item."
    ans += g.link(action:"index"){"<H2>Next</H2>"}+"( $correct / $total )"
    render ans
  }
  
  def ikea() {
    total ++
    def ans = ikeas.contains(params.id) ?
      "<H1>Right!</H1> ${params.id} is IKEA Item.<!--${++correct}-->" :
      "<H1>Wrong.</H1> ${params.id} is Metal Band."
    ans += g.link(action:"index"){"<H2>Next</H2>"}+"( $correct / $total )"
    render ans
  }
}

Gistにも置いてあるので、見づらい方はそちらを見てください。

リスト ikeasmetals はそれぞれイケア、メタルの出題リストです。 totalcorrect はそれぞれ出題総数と正解数ですね。コントローラだけで作るために、staticにしています。

アクション index は出題画面で、イケアの場合は ikea アクションに、メタルの場合は metal アクションに飛ばします。このとき、 id に選択した要素の文字列を入れておき、飛んだ先のアクションで params.id で拾えるようにしておきます。

アクション metalikea はそれぞれ正解の判定をするアクションで、三項演算子 ? を使って判定しています。 ++correct するためにHTMLのコメントを使ったり、ちょっと無理やりですね。 index アクションから飛ばすパラメータを増やせば metal アクションと ikea アクションは分ける必要も無くなるので、気になる方はちょっと考えてみてください。

こんな風に、Grailsはちょっとしたお遊びプログラムを走らせるWebアプリケーションフレームワークとして使うこともできるんですよ!

Grailsでrun-scriptコマンドを使って任意のGroovyスクリプトを走らせ、その中でServiceを使う

Grailsには、create-scriptコマンドを使ってscriptsディレクトリ配下にGantスクリプトを作り、任意のGrailsコマンドを追加する機能があります。

scriptsディレクトリ配下のGantスクリプトはGrailsコマンドとして実行可能になるため、 scripts/MyScript.groovy を作ったら、 grails my-script コマンドとして実行できますね。

では、run-scriptコマンドはご存知でしょうか?

このコマンドは、任意のGroovyスクリプトを、Grailsのコンテキストを与えた上で実行可能にするコマンドです。Grails 1.3.6の頃からあるようです。

このコマンドは

> grails run-script src/groovy/package/MyScript.groovy

のように、実行するGroovyスクリプトを指定して実行します。このGroovyスクリプトの中では、Grailsのドメインクラスをそのまま利用することができます。

new MyDomain(str:"テストです").save()
println MyDomain.count()

では、Serviceを使うにはどうするか?run-scriptしたときには、 applicationContext が無くて applicationContext.getBean('myService') みたいなことをさせて貰えません。ここはGrails本体の scripts/RunScript.groovy を覗いてみましょう。

def shell = new GroovyShell(classLoader, new Binding(ctx: appCtx, grailsApplication: grailsApp))

なんていう行がありますね。どうやらrun-scriptのときのApplicationContextは変数ctxに入っているようです。

def my = ctx.getBean('myService')
my.method()

これでServiceも呼べますね!GrailsApplicationが必要なら grailsApplication に入っているので、これも覚えておくと良いでしょう。Gantを書くより手軽に定型的な処理を書き出しておけるので、いろいろと使い道がありそうです。

Yokohama.groovy #15 に参加してきた #yokohamagroovy #mattarigrails

たまには参加報告書きましょう。

先月の Yokohama.groovy #14 から、 #mattarigrails と称してGrailsをもくもくする集団として #yokohamagroovy との合同開催で横浜タネマキさんにお邪魔しております。

参加メンバーにもよりますが、必ずしもGrailsやG*に縛られての作業でも無かったようです。AndroidアプリのOAuth連携をつくってみたり、デザイン系の作業をしたりしてる人もいました。

GroovyやGrailsなど、G*エコシステムに興味がある方、ゆる~く学びの時間を共有しに来てみませんか?是非是非お待ちしております。

今回の僕のテーマは、GrailsでのOAuth連携でした。

spring-security-oauth プラグイン

以前このプラグインでTumblrのアカウント連携をやったことがあったので、サクサクいけるだろ、なんて2時間ほどもくもくしてみたんですが、どうにもうまくいきません。あれ…おかしいな…とか言いながら見切りをつけて次に。

spring-security-twitter プラグイン

確かにドキュメントの通りにあれやこれややってあげれば動く。動くんだけどそこに至るまでキッチリ引っかかる罠、罠。主に s2-init-twitter コマンドなんですが、動作にいくつか問題がありました。

  • Config.groovy に追加される設定値が誤っている
  • ファイルのコピーに失敗する
  • コピーされた spring-security-twitter.messages.properties が空
  • 生成されるドメインクラス TwitterUser が動かない

んーいけてない。これぜんぶ修正したらだいぶ使いやすいんじゃないですかね。ついでにAPI経由でのPostの方法も調べましょう。とか言ったところでこの日の作業は時間切れ終了。

後日4件ほどpull requestを投げるに至り。

無事mergeされ spring-security-twitter プラグインが 0.5 から 0.5.2 にバージョンアップするに至り。

Twitter連携するWebアプリなんてあっという間にできるよ。そう、Grailsのspring-security-twitterプラグインならね!に至る。

といった流れだったのでございました。

次回 Yokohama.groovy #16 with #mattarigrails

2013/06/23(日) 13:30~19:00 横浜タネマキにて開催予定です。興味ある方はぜひご参加どうぞ~。

Windows PowerShell から Gradle wrapper (gradlew) を叩くときにはオプションのクオートをしよう

何回やっても忘れるのでメモ。。

> ./gradlew -q -Ddisable.groovydocs=true -Dgrails.home=C:\GGTS\grails-2.1.5 clean publishGuide_ja

Windows PowerShell からこんな gradlew コマンドを叩くと

FAILURE: Could not determine which tasks to execute.

* What went wrong:
Task '.groovydocs=true' not found in root project 'grails-doc'.

とか

FAILURE: Could not determine which tasks to execute.

* What went wrong:
Project '.home=C' not found in root project 'grails-doc'.

みたいなことになります。一瞬エッΣ(゚Д゚)ってなるかもしれませんが、オプションをクオートしてやると通ります。

> ./gradlew -q "-Ddisable.groovydocs=true" "-Dgrails.home=C:\GGTS\grails-2.1.5" clean publishGuide_ja
> ./gradlew -q -D"disable.groovydocs=true" -D"grails.home=C:\GGTS\grails-2.1.5" clean publishGuide_ja

どちらかのクオートで通りました。

Twitter連携するWebアプリなんてあっという間にできるよ。そう、Grailsのspring-security-twitterプラグインならね!

pull requestがmergeされてプラグインが更新されて不便なところが解消された記念に紹介します。

  • spring-security-twitter プラグインを導入する
  • Role をつくる
  • GSP に連携ボタンを設置する

たったこれだけです。

spring-security-twitter プラグインを導入する

http://grails.org/plugin/spring-security-twitter に書いてある通り、 BuildConfig.groovyrepositories ブロックに

mavenRepo "http://maven.springframework.org/release/"

を、 plugins ブロックに

compile ":spring-security-twitter:0.5.2"

を、それぞれ追記します。そのあと refresh-dependencies コマンドで、追記したプラグインの依存性を解決します。

grails> refresh-dependencies

| Loading Grails 2.1.5
| Configuring classpath.
| Environment set to development....
| Installing zip spring-security-twitter-0.5.2.zip.....
| Installed plugin spring-security-twitter-0.5.2
| Resolving plugin JAR dependencies

**************************************************************
* You've installed the Spring Security Twitter plugin.       *
*                                                            *
* Next run the "s2-init-twitter" script to configure plugin. *
*                                                            *
**************************************************************

| Resolving plugin JAR dependencies.....
| Installing zip spring-security-core-1.2.7.2.zip.....
| Installed plugin spring-security-core-1.2.7.2
| Resolving plugin JAR dependencies

*******************************************************
* You've installed the Spring Security Core plugin.   *
*                                                     *
* Next run the "s2-quickstart" script to initialize   *
* Spring Security and create your domain classes.     *
*                                                     *
*******************************************************

| Resolving plugin JAR dependencies...
| Dependencies refreshed.

みたいな感じで、Mavenリポジトリからダウンロードしてプラグインのインストールをしてくれます。丁寧にインストラクションを出してくれてるので、まずは s2-quickstart コマンドから打ちましょう。これは、spring-security-twitterプラグインのベースとなっているspring-security-coreプラグインのコマンドです。

grails> s2-quickstart jp.myapp User Role

これで、プラグインで扱うユーザとロールのドメインクラスができあがります。 jp.myapp っていうのはpackage名ですね。自分のアプリで任意に決めて付けてください。次に

grails> s2-init-twitter
(中略)
> Enter your Twitter API Key twitter
> Enter your Twitter API Consumer Key sOMeTwiTTErcoNSumERKEy
> Enter your Twitter API Consumer Secret sOMeTwiTTErcoNSumERSEcRETTwiTTErcoNSumERS

です。 API Key というのを聞いてきますが、任意の文字列で構いません。 Consumer KeyConsumer Secrethttps://dev.twitter.com/ で払い出したものを使いましょう。

Role をつくる

Role が無くても動作はするのですが、「認証を通ったか通ってないか」で画面を振り分けたりするときにこれが無いと不便なので、作っておきましょう。 BootStrap.groovy

import jp.myapp.Role

class BootStrap {

  def init = { servletContext ->
    Role.findByAuthority("ROLE_USER") ?: new Role(authority:"ROLE_USER").save()
    Role.findByAuthority("ROLE_TWITTER") ?: new Role(authority:"ROLE_TWITTER").save()
  }
}

みたいな感じで書いておけばOKです。ROLE_USERとROLE_TWITTERが存在しなかったら作って保存する、というだけのコードです。 ?: はエルビス演算子ですね。2つ作ってる理由は、spring-security-twitterプラグインがデフォルトでその2つのロールを利用するからです。必要であれば設定を変えることもできます。

GSP に連携ボタンを設置する

こんなGSPコードを index.gsp の末尾のほうに追記するだけで、連携を確認できます。

<sec:ifLoggedIn>
  <div class="message">Authenticated. Hello <sec:username/>!</div>
</sec:ifLoggedIn>
<sec:ifNotLoggedIn>
  <div class="message">Not authenticated. <twitterAuth:button /> </div>
</sec:ifNotLoggedIn>

run-app して動作を確認してみましょう。実行したアプリを開くと、こんな画面が出るので「Connect with Twitter」をクリックしましょう。

f:id:y___u:20130522151356p:plain

いつものTwitter連携画面が出るので、承認してあげます。

f:id:y___u:20130522151401p:plain

すると、元の画面に戻りますが、自分のTwitterIDでメッセージが表示されますね!

f:id:y___u:20130522151405p:plain

内部では、TwitterIDでアカウントが生成され、そのアカウントでのログイン処理が行われています。つまり、自分の作ったWebアプリ用のユーザ認証の仕組みと、そのTwitter連携ができているのです。

TwitterAPIを使って投稿してみる

ここまでやったんだから、投稿についても試してみましょう。

まず、デフォルトパッケージで生成されている TwitterUser クラスを自分のpackageに移動し、 TwitterTemplate を取得するメソッドを追加します。こんな感じになりますね。

package jp.myapp

import org.springframework.social.twitter.api.impl.TwitterTemplate;

class TwitterUser {

  Long twitterId
  String username

  String tokenSecret
  String token

  static belongsTo = [user: User]

  static constraints = {
      twitterId(unique: true, nullable: false)
      username(nullable: false, blank: false)
  }

  TwitterTemplate getTwitterTemplate(config){
    new TwitterTemplate(
      config.grails.plugins.springsecurity.twitter.consumerKey,
      config.grails.plugins.springsecurity.twitter.consumerSecret,
      token,
      tokenSecret )
  }
}

TwitterTemplatespring-social-twitterに含まれるクラスですね。もちろんimportもしてあげます。

あとは、つぶやくためのコントローラを作ってあげればよいです。こんな感じに書けますね。

package jp.myapp

import grails.plugins.springsecurity.SpringSecurityService
import org.springframework.social.twitter.api.impl.TwitterTemplate

class TweetController {
  def springSecurityService

  def index() {
    def tw = TwitterUser.findByUsername( springSecurityService.getCurrentUser().username ).getTwitterTemplate(grailsApplication.config)
    def st = tw.timelineOperations().updateStatus("#Grails のspring-security-twitterプラグインを使ってつぶやいています。 #yokohamagroovy #mattarigrails")
    render st.getCreatedAt()
  }
}

springSecurityService からログインしているユーザを取得し、そのユーザ名を元に TwitterTemplate を取得し、 TimelineOperations のupdateStatusによってつぶやきを投稿しています。

このアクションを実行するには、アプリのコントローラ一覧から jp.myapp.TweetController をクリックすればよいですね。renderでつぶやきの作成日時を返しているので、ブラウザ上は Wed May 22 16:16:11 JST 2013 みたいな結果が得られるでしょう。

基本的に TwitterTemplate を取得できるようにしておけば、ほとんどあらゆるAPIの操作ができます。そのあたりは、TwitterTemplateのJavaDocから

  • BlockOperations
  • DirectMessageOperations
  • FriendOperations
  • GeoOperations
  • ListOperations
  • SearchOperations
  • TimelineOperations
  • UserOperations

あたりを辿ればだいたいわかりますよ!

GrailsのインタラクティブモードをWindowsで使うときはWindows PowerShell + Grails wrapperが快適

WindowsのコマンドプロンプトGrailsのインタラクティブモードまともに動かないよねー、とお嘆きのみなさま。果たして何人いるのかわからないみなさま。

Grails wrapper は御存知ですか?

> grails wrapper

としてやると、自分のGrailsプロジェクトに grailsw コマンドを追加して、あたかもそこにGrailsコマンドがあるかのように動作してくれる、蝶・便利なコマンドです。環境変数いじらなくても動いてくれるので楽ちんですね。シェル(grailsw)とバッチ(grailsw.bat)が用意されてるので、Windowsでの動作もバッチリです。Grails wrapperは次期バージョンからはデフォルトで入ってくれるという嬉しい話もありますね。

このGrails wrapperをWindows PowerShellで使うと…!!

> ./grailsw
| Enter a script name to run. Use TAB for completion:
grails> generate-
generate-all          generate-controller   generate-views
grails>

なんとインタラクティブモードに入れます。tab補完も動作します。もうこれGGTSからコマンド実行する理由ないじゃん重いし。なんてこった/(^o^)\

GGTSもAptana Studioみたいに、Grailsのインタラクティブモードのプロンプトウインドウ出しておいてくれれば使い勝手も多少はいいですのに。

ちなみに手元の環境

で試しました。設定してあるシステム環境変数JAVA_HOME のみ、つまり Path 追加してないのでWindows PowerShell上では java -version コマンドすら通らない程度には環境変数設定してないんですが…。

Grails wrapperさんかっこ良すぎですね!

GrailsでWebスクレイピングをするときはjsoupで簡単・便利!(もちろんGroovyでもJavaでも)

先日、名古屋で学生向けGrails/Groovyハンズオンをやらせて頂きました。

その中で、学生さんから「任意のサイトからHTMLを取得して、HTML中の任意の要素を取得するのにスマートな方法はありませんか?」といったような質問を受けました。いわゆるWebスクレイピングですね。その場では、TagSoup http://ccil.org/~cowan/XML/tagsoup/ を紹介しつつ実演しました。手元にTagSoupを使ったコードがすでにあって、その場で時間をかけずに見せやすかったからです。

が、jsoup http://jsoup.org/ の方が使い方とかjavascriptと同じように書けてかっこ良いですね。なので、この記事ではjsoupで書きます。

まず、(Grailsを前提として) BuildConfig.groovy のdependenciesにjsoupを追加してあげます。Mavenリポジトリのjsoupの最新版からGradleの記法を引っ張ってくればいいですね。

dependencies {
  runtime 'org.jsoup:jsoup:1.7.2'
}

あとは、特定のアクションにアクセスしたら、対象のHTMLを取得して必要な要素だけ返すように書いてあげます。ここではYahooニュースのトップトピックスを取得し、アンカー付きで表示しています。

import org.jsoup.*
import org.jsoup.nodes.*
import org.jsoup.select.*

class ScrapingController {

  def index() {
    Document doc = Jsoup.connect("http://dailynews.yahoo.co.jp/fc/").get()
    Elements topics = doc.select('#topTopics li a')
    render topics.join("<br>")
  }
}

GroovyのスクリプトでGrapeを利用してjsoupを使う場合にはこんな感じになりますね。

@Grapes(
  @Grab(group='org.jsoup', module='jsoup', version='1.7.2')
)
import org.jsoup.*
import org.jsoup.nodes.*
import org.jsoup.select.*

Document doc = Jsoup.connect("http://dailynews.yahoo.co.jp/fc/").get()
Elements topics = doc.select('#topTopics li a')
def str = ""
topics.each{ str += it.text() + "\n" }
str

MavenリポジトリにはGrapeの記法もあるので楽ちんです。importも忘れずに!こっちはアンカー無しのプレーンテキストです。

ひとつ気をつけて欲しいのは、静的HTMLの上にAjaxで動的にHTML断片を追加しているようなページでは、ブラウザで表示したときに見えているHTML要素がセレクタに引っかかってこない、ということがあることです。

いずれにせよ、jsoupでは select()CSSjQueryセレクタと同じ書き方でHTMLの要素を取得できるので、スクレイピングのためにAPIをあれこれ調べる必要がありません。すてきですね!

Grails MiniProfiler プラグインはメモリリークに気をつけましょう。

BuildConfig.groovy の plugins に

runtime ':profiler:0.4'
runtime ':miniprofiler:0.1'

って書くだけで、リクエストごとの発行SQLやレスポンス時間などのプロファイリングを画面上に出してくれる MiniProfiler プラグインGGX 2012で話を聞いてから使っていましたが、たいへん盛大にメモリリークを起こしてくれるので、使う際にはそっち方面の注意が必要です。

この MiniProfiler、サーバ側で取得したプロファイル情報を、GSP表示後にAjaxで追加表示する、という動きをします。そのため、Ajaxで表示するための情報はいずこかで参照を持ち続け、メモリリーク(として見えるよう)になるのでしょう。あとプロファイル情報が多いと表示までにすごい時間かかります。

1リクエスト500SQLくらい発行する解析系のシステムに使ってみたら、1リクエストで15MBくらいのメモリリークを起こしていました(おそらく発行SQL数に比例する)。MiniProfiler が有効な状態で負荷試験をしたら、あっという間にメモリを喰い潰して常にFullGCが走り続けて応答がなくなる、という状況に陥るため、不要になったら必ず BuildConfig.groovy から消しましょうね。

if (Environment.current == Environment.DEVELOPMENT) {
    runtime ':profiler:0.4'
    runtime ':miniprofiler:0.1'
}

とかやって development 環境でだけ動作するようにしてみたけど、 run-war (production環境)でもメモリリークが止まらなかったのが気になりました(少なくとも削除したら平和になった)。

Java/Groovy/G*界隈でBoostする為に有用なリンクを集めてみた(Grails編)

なぜかGrailsは無かったので情報を整理してみる。

  • ◎:Grails入門者向けピックアップ
  • ☆:2013/05/24追加分

(関連)

公式

国内(ユーザーグループ界隈)

Grails関連勉強会・イベント

JavaGrails

導入・IDE

チュートリアル

GrailsGoogle Calendarっぽいのをつくってみせるよ!っていう壮大なチュートリアル。英語。

サンプルアプリ

プラグイン

豊富なプラグインによる機能追加で異次元の生産性を

フレームワーク比較・ベンチマーク

スライド



ほかに有用な情報、ありませんか?

やや力尽きているので、これも紹介しといて!的な情報、ぜひぜひくださいませ。追記させていただきます。

サクサクWebアプリを作って公開!Grails+CloudFoundryハンズオンをやりました。

先週の金曜日4/19、G*ワークショップZ Apr 2013 - Grails+CloudFoundryハンズオンをやりました。

30分ほどCloudFoundryについて日本CloudFoundryグループの中の人に話をして貰い、そのあとの1時間半でGrailsでWebアプリを作成して、cloudfoundry.comにデプロイしてみましょう、というハンズオンです。

発表資料は http://bit.ly/GrailsCF で見ることができます。

作成したGrailsアプリのソースコードhttps://github.com/morika-t/morika にあります。

Togetterはこちらkimukou2628さんありがとうございます!

事前にcloudfoundry.comのアカウントとGrailsの動作環境は整えておいてくださいね、というかたちで始めました。Mac/LinuxではGVM http://gvmtool.net/ を使えばあっという間にGrailsの環境が作れちゃいますね。Windowsでも、Grailsのバイナリを持ってきて環境変数を設定するか、GGTS(Grailsが同梱されている)を入れれば済むので、ハードルは低いです。JDK入れてない!という人はまず最初にJavaを入れてくださいね。=D

もう1人の発表者の要望(?)で、発表者2人が来場者と同じ方向を向いて、来場者に背を向けて発表する、というかたちになり、身内からこんな言葉を頂くなどもしました。ふふ

サンプルのGrailsアプリは、画像を添付したデータを保存・一覧できる、という簡単なものです。Rails Girls App Tutorialで作っているものに非常に近いですね。もっとも、Rails GirlsではCarrierWaveというgemを使って画像を扱いますが、今回のGrailsアプリはGrailsの機能で実装しています。

Grailscloud-foundryプラグインでは、grailsコマンドとして cf-push や cf-update、cf-logs などを実行できるので、Rubyやgem、vmcのインストールが不要なのがポイントです。Grailsのインタラクティブモードを利用すれば、コマンド実行時のロード時間もそれほど気にならなくなるでしょう。

ハンズオンを進める中で、cloudfoundry.comのpostgresサービスが死んでbindできない、という状況が発生し、急遽mysqlを使う、というトラブルも発生しました。これには発表者2人とも焦りましたが、GrailsアプリのソースコードはDataSource.groovyを含め一切変更することなく、cf-pushしなおしてmysqlをbindするだけ、で先に進めることができました。

いろいろと質問も出まして、嬉しい限りでした。

  • DBの冗長化は? → DB(CloudFoundryのService)の冗長化はサービス事業者側の責任。複数のサービスをbindすることはできる。
  • アプリのupdate時のダウンタイム(サービス中断時間)はどうにかできない? → 無償のcloudfoundry.comではどうしようもない。サービス中断が問題になるようならheroku/Cloudn/CloudBees/AppFogなど、有料のPaaSプロバイダを利用した方がスジが良い。
  • 立ち上げられるインスタンス数の上限は? → cloudfoundry.comでは、メモリ2GBの割り当て範囲内で。CloudFoundryの仕組み自体は、DEAを別々のマシン上に立ててスケールアウトすることができるようになっているので、ハードを増やしてrouterががんばれる限り増やせる。AppFogでは128インスタンスまで使える
  • HTTPS(SSL)の利用は? → 証明書を利用者側で用意する以外にやり方がない。 cf-push 等をするときの経路にSSLを使いたい場合には grails.plugin.cloudfoundry.target の値を 'http://api.cloudfoundry.com' ではなく 'https://api.cloudfoundry.com' とすれば良い。

そのほかの質疑については、 https://gist.github.com/morika-t/5424468 に書かれています。

また、cloudfoundry.comにデプロイしたGrailsアプリがJava6上で動作する場合には、ローカル側でwarファイルが作られる際の互換性をJava1.6指定とする必要があります。cloudfoundry.comはJava7にも対応しているので、cf-push するときに --runtime=java7 としてやればJava7で動作してくれるようです。

手を動かして、道具としての素晴らしさを感じてもらうことができて良かった!