Ruby Freaks Lounge

第16回Google App Engine上でRailsを動かす

はじめに

前回はGoogle AppEngine(GAE)の概略と、GAEとRailsの相性は悪くはないのではないか(良いとは言い切れないところが少し苦しいですが)という話をしましたが、その結果GAEの話ばかりでソースコードもほとんど出てこない、Rubyとあまり関係のない内容になってしまいました。今回はそれを埋め合わせるべく、実際にRailsで小さなサンプルを作成してGAE上で動作させるまでを説明したいと思います。それではさっそくRubyの話に進みましょう。

RailsをGAEの上で使うために

GAEはDBとしてBigTableを使っているのでActiveRecordが使えないことについては前回書きました。それでは ActiveRecordを使っていないRailsアプリなら特別な作業をせずに簡単にGAE上で動かせるのでしょうか?結論から言うと、残念ながらそんなことはありません。GAE上で初めて公にRailsを動かしたOla Bini氏のブログ和訳に書かれている作業には以下のようなものがあります。

  1. warblerのインストール
  2. GAEでデプロイできるファイル数は(当時は)最大で1000ファイルであったためfreezeしたRailsを含むファイル総数が1000を下回るようにActiveRecord、ActiveResource、Railties、ActionPackの一部などアプリケーションで使用していないファイルを削除
  3. GAEでデプロイできるファイルの最大サイズは10Mなのでjruby-complete.jarを規定サイズに収まるよう複数ファイルに分割
  4. appengine-web.xml、config/environment.rb、config/warble.rbなどの設定ファイルを適切に設定

2に関してはごく最近デプロイできるファイル数が3000に引き上げられたため今では問題ないようですが、Railsをfreezeするとそれだけで 1000ファイルを超えますから、当時はなかなか面倒な作業でした。また3についても、リポジトリから最新を落として来てコンパイルしてjarに固めたあとで、さらに余分な作業が発生するわけでそれなりにハードルを上げていました。

rails_on_gaeプラグインとアプリケーションテンプレート

私も前節の作業をOla Bini氏のブログに従って実際にやってみました。一応動きはしたものの、この作業をいろんな人が各自ばらばらにやるのではあまりにも時間の無駄です。ということで、いくつかの作業を自動化するプラグインを作成して共有しました。それがrails_on_gaeプラグインです。AppEngine SDK(Java⁠⁠、JRuby、Warblerがインストールされている環境なら、railsコマンドでアプリケーションを作成した直後にアプリケーションのルートディレクトリで以下のようなコマンドを実行するだけでGAE上でRailsを動かすための準備が完了するはずです。

rails_on_gaeプラグイン
$ script/plugin install git://github.com/technohippy/rails_on_gae.git
$ rake 'gae:init'

さらにRails2.3からはアプリケーションテンプレートという、新規アプリケーション作成後に定型的に行う作業を自動化できる仕組みが用意されていますので、上記のプラグインのインストールとrakeタスクの実行を行うアプリケーションテンプレートも作成しました。こちらを使うと、以下のようなコマンドを実行するだけでGAE上で動かすRailsアプリのひな形が完成します。

アプリケーションテンプレート
$ rails アプリケーション名 -m http://gist.github.com/103256.txt

プラグインでインストールされるライブラリ

プラグインをインストールしてrakeタスクを実行すると、先に書いた面倒な作業を自動的に行うことに加えて、いくつかの便利なライブラリがlibディレクトリ以下にインストールされます。ここではそれらのライブラリについて簡単に説明します。

appengine-jruby

GAE/J APIのJRubyラッパーで、以下のAPIをJRubyから利用できます。それぞれのAPIの詳細についてはGoogle Codeのドキュメントを参照してください。

  • AppEngine::Logger
  • AppEngine::Testing
  • AppEngine::Users
  • AppEngine::Mail
  • AppEngine::Memcache
  • AppEngine::URLFetch
  • AppEngine::Datastore

また、appengine-jrubyはAppEngine::Datastoreを利用したDatastore用のDataMapper Adapterを含みます。最新のDataMapper(0.10.0)を用意すればDataMapper APIを使用してDatastoreにアクセスできるはずです。ただし、こちらについてはまだ私の方で動作が確認できていないので、 rails_on_gaeプラグインではDataMapperはインストールされません。

余談ですがappengine-jrubyの開発にはGoogleの社員が関わっているそうです。もちろんGoogleが正式に会社としてサポートしているわけではないようですが、それでもやはり少し安心感がありますよね。

Bumble

Ola Bini氏が作成したDatastoreアクセス用の簡易ライブラリです。ただしrails_on_gaeプラグインに付属するものは appengine-jrubyのAppEngine::Datastore APIを使用するように変更されています。例として、前回と同じソースコードですが、Bumbleを使用したモデルの定義は以下のようになります。

リスト1 Bumbleモデル定義例
class Blog
  include Bumble

  ds :name, :owner_id, :created_at
  belongs_to :owner, Person
  has_many :posts, :Post, :blog_id, :iorder => :created_at
end

また、Bumbleモデルの基本的な使い方は以下です。

リスト2 作成
Blog.create(:owner => @login_user, :name => 'My Blog')
リスト3 キー指定検索
Blog.get(@key)
リスト4 条件検索
Blog.all(
  {:owner_id => @login_user.id}, 
  :limit => 10, :order => 'created_at'
)
リスト5 更新
@blog.name = 'New Name'
@blog.save!
リスト6 削除
@blog.delete!

Bumbleモデルジェネレータ

ライブラリではありませんが、プラグインをインストールすると上述のBumbleモデルを簡単に生成できるジェネレータがおまけで付いてきます。以下のようにして使用してください。ただし、あくまでもおまけなので過度の期待は禁物です。

Bumbleモデルを生成
$ script/generate bumble_model Post name owner_id created_at
リスト7 生成されるモデル
class Blog
  include Bumble
  ds :name, :owner_id, :created_at
end

簡単な掲示板を作ってみる

それでは、これまでの内容を元に実際にJRubyを使用してGAE上で実際に動作する簡単な掲示板を作ってみましょう。

GAE/J、JRuby、Warblerはすでにインストール済みであるとします。インストール方法に付いては、GAE/Jはこちらを、JRubyはこちらを、それぞれ参照してください。Warblerはjgem install warblerでインストールできます。それ以外にも何らかのgemが足りない場合にはアプリケーションテンプレート適用時にエラーになるかもしれません。エラーメッセージを参考にjgem installまたはgem installしてください。

Railsアプリケーション生成

まずはアプリケーション名を決定します。アプリケーション名はGAEの管理コンソールで取得できます。早い者勝ちなので使いたい名前があるなら先に取っておきましょう。

図1 管理コンソール
図1 管理コンソール
図2 アプリケーション情報入力
図2 アプリケーション情報入力

前述のアプリケーションテンプレートを利用して、取得した名前のRailsアプリケーションを生成します。以下では仮に「testapp」を取得したとして話を進めます。

アプリケーション生成
$ rails testapp -m http://gist.github.com/103256.txt

モデル作成

ジェネレータを使用してモデルを生成します。

Commentモデルを生成
$ script/generate bumble_model Comment body created_at
リスト8 生成されるモデル
class Comment
  include Bumble
  ds :body, :created_at
end

コントローラー作成

Welcomeコントローラーを作成して、indexアクションとcreateアクションを処理するようにします。indexアクションではコメントの一覧を表示し、createアクションでは新しくコメントを作成したあとでindexアクションにリダイレクトします。

Welcomeコントローラーを生成
$ script/controller welcome
リスト9 app/controllers/welcome_controller.rb
class WelcomeController < ApplicationController
  def index
    @comments = Comment.all({}, :iorder => :created_at)
  end 
  
  def comment
    unless params[:body].blank?
      Comment.create(:body => params[:body], :created_at => Time.now) 
    end
    redirect_to :action => 'index'
  end 
end

ビュー作成

単純なビューであるため、レイアウトは使用せず、一つのファイルに全て収めています。

リスト10 app/views/welcome/index.html.erb
<html>
<head><title>Rails on GAE</title></head>
<body>
  <% form_tag :action => 'comment' do %>
    <%= text_field_tag 'body', '', :size => 50 %>
    <%= submit_tag 'Comment' %>
  <% end %>
<ul>
  <%- @comments.each do |comment| -%>
    <li><%=h comment.body %> (<%= comment.created_at %>)</li>
  <%- end -%>
</ul>
</body>
</html>

ルート追加

URLでコントローラー名とアクション名を指定しなくてもルートにアクセスすれば表示されるようにするため、routesファイルに以下を追加します。

リスト11 config/routes.rb
map.root :controller => "welcome"

publicディレクトリにindex.htmlがあるとそちらが優先されてしまうので、忘れずに消しておきましょう。

index.html削除
$ rm public/index.html

ローカルで動作確認

以上で掲示板の作成が終わりました。まずはローカル環境で動作を確認してみましょう。

GAE/J上でWebアプリケーションを動作させるにはファイルをWAR標準に従ったディレクトリ構造に配置しなければいけません。warbleコマンドを使用するとRails標準構成のファイルをtmp/war以下に移動してWAR標準に沿って再構成してくれます。

WAR標準に再配置
$ warble war
ローカルサーバー起動
$ dev_appserver.sh tmp/war
図3 ブラウザで確認(http://localhost:8000)
図3 ブラウザで確認(http://localhost:8000)

なお、GAEのローカルサーバーで実際に実行されるのはwarble warコマンドで作成されたtmp/war以下のファイルになります。従ってappディレクトリ以下のファイルを編集しても動作中のアプリケーションは変更されません。何か変更したときにはwarble warして変更をtmp/warに反映させたあとで、サーバーを再起動することを忘れないようにしましょう。

本番環境にデプロイ

ローカルでの確認ができたら本番環境にデプロイしましょう。前回も書いた通り、GAEでのデプロイは非常に簡単です。

デプロイ
$ appcfg.sh update tmp/war

Gmailアカウントとパスワードを聞かれた場合は入力してください。これで本番環境にデプロイできています。アプリケーション名が「testapp」だった場合、そのURLは http://testapp.appspot.com です。アプリケーション名は異なりますが今回説明したアプリケーションはこちらで公開しています。よかったら実際に触ってみてください。

おわりに

以上のようにGAEを利用すれば非常に簡単にRails製Webアプリケーションを公開することが可能です。残念ながらActiveRecordは使えませんが、ORMとしては代わりにDataMapperが使えますし、appengine-jrubyのおかげでGAE APIのほぼ全てにRubyインターフェースを通じてアクセスできます。クォータを気にしなければ完全に無料で始められますので、少しでも気になった方は本記事を参考にぜひ一度自分で試してみてください。

おすすめ記事

記事・ニュース一覧