2010年6月14日月曜日

Rhomobile Tutorial2

以下のドキュメントは、英語の原文を日本語へ翻訳したものをRhomobile社の許可のもと、公開しています。
公式なドキュメントはRhomobile社のサイトをご覧ください。
また、この文書は2010/6/4(JST)の情報がもとになっています。
この日本語の翻訳について問題・質問などがある場合、コメントを残してください。それ以外については、本ドキュメント内にある問い合わせ先にお願いします。

The following document (a translation of the English original into Japanese) is published with Rhomobile permission.
If you need official documents, please visit Rhomobile site.
In addition, the following document is based on 2010/June/4 (JST) information.
If you have any question, problem about the Japanese translation, please leave your comment. Except for that, refer contacts in the document.

Tutorial2


このチュートリアルでは、現在出荷しているスマートフォンにRhodesとRhoSync 2.0を使用してネイティブモバイルアプリケーションを構築する方法を説明します。具体的にどのようにRhodes controllerやテンプレートを作成し、バックエンドアプリケーションからデバイスへデータを同期するためにRhoSyncソースアダプタ(source adapter)を作成する方法について説明します。このアーキテクチャはここで見ることができます。


目次


1 Rhodesアプリケーションの作成(Build)

Rhodesのアプリを書くのは次の手順から成ります:

  • Rhodesのインストール
  • Rhodesアプリの生成
  • データmodel(モデル)のRhodes controller生成
  • controller(コントローラ) actionのview(ビュー)を編集
  • アプリケーションをテスト

Rhodesのインストール

Rhodesフレームワークでは2つの方法が動作します。最初の方法はRhodes gemを使ってRhodesをインストールする方法で、このチュートリアルで説明する、推奨されれる方法です。2番目の方法はソースを直接使う方法です。Using Rhodes From Source

続ける前にRubyRubyGemsのインストールを確認してください。

  • Windowsでは、 RubyInstallerがRubyをインストールする便利な方法です
  • RubyGemsは.tgzファイル・.zipファイルと.gemのダウンロードを提供します。.zipファイルがいいでしょう。

Windowsは、gemをインストールする必要なUnixツール(例えば、'make')は付属していません。これらのツールを取得する方法は色々ありますが、GnuWin32プロジェクトがこれらのツールを提供し、GetGnuWin32インストーラ経由で便利にインストールできます。

Rhodesを使用する最初の手順は、Rhodes gemをインストールすることです(OS X上で、このコマンドの前に"sudo"を入力することがあります)

gem install rhodes

TIP:rake taskやrhogemコマンドを実行している間に、"no such file to load -- something"というメッセージが表示されたなら、これは通常'[sudo] gem install something'することで解決されます。


Rhodesをインストールしたら、アプリをbuild(作成)する対象のプラットフォームSDKが必要になります。この説明はここにあります。


このgemと必要なSDKをインストールした後、コマンドを実行する必要があります。



rhodes-setup

これは様々なプラットフォーム用のSDKをインストールした場所を尋ねます。このインストールスクリプトは、SDKの場所の最適な推測を表示するでしょう。別の場所を入力するか、その提案をそのまま使うために空白のままにすることもできます。あなたが特定のプラットフォーム向けのbuild(作成)をしないならば(たとえばWindows上でiPhoneを構築できません)、そのSDKの場所を空白のままにすることができます。それぞれのプラットフォームごとの前提条件はBuilding Rhodes Apps in Support Platformsで見つけることでできます。

1.2 Rhodesアプリケーションの生成

最初のステップは、アプリケーションと基本となるファイルを生成することです。これは、前の手順でインストールされたRhodes gemの一部RhoGen(Rhodesジェネレータ)ユーティリティで行います。

先ず、StoreManagerと呼ばれるアプリケーションを次のコマンドで生成します:


rhogen app storemanager http://localhost:9292/application

これは、"storemanager"と呼ばれるアプリケーションのディレクトリを生成し、複数のファイル生成します。また、上記の3番目の引数はRhoSyncサーバーのデータソース(次のセクションで説明するようにデータを同期したい場合に必要)へのURLであることに注意してください。具体的には、次のオプションがファイルrhoconfig.txtへ設定されます:



syncserver ='http://localhost:9292/application'

オフライン・データを同期する必要がない場合は、3番目の引数は除外することができます。

アプリのデフォルトのホーム画面がstoremanager/app/index.erbファイルに定義されます。アプリケーションが表示するものを作るために、そのHTMLを編集することができます。標準のHTML技術でそこから他のHTMLファイルやERBファイルにリンクすることができます。その後、rake taskでアプリケーションを構築することができます。たとえば、iPhone用にビルドしシミュレータを実行するには、次のコマンドを入力します:


cd storemanager
rake run:iphone

20100512 - px2wrmj1bj7yixjy7fp2d31yw6.png

他のプラットフォームやシミュレータ用にビルドするには、例えばBlackBerryエミュレータで動作させるには"rake run:bb"のように、適切なrake taskを実行します。すべての可能なrake taskを表示するには次のコマンドを入力します:


rake -T

model(モデル)を生成

アプリケーションがコンパイルされ実行できたら、model(モデル)とcontroller(コントローラ)の追加を行うことができます。model(モデル)を生成したとき、Rhodesはモデルの表示と編集用に標準的なUIのファイルも作成されます。これは、標準のmodel(モデル)-view(ビュー)-controller(コントローラ)のパラダイムに準じます。

"product"モデルを生成して、それにいくつかの属性を与えてみましょう。



cd storemanager
rhogen model product brand,name,price,quantity,sku

RhoGenがコントローラ(product_controller.rb)といくつかのHTMLテンプレート(.erbファイル)を作成するのが分かるでしょう。これらは指定されたmodel(モデル)のオブジェクトを読んだり編集したりするものです。


Generating with model generator:
[ADDED] app/Product/index.erb
[ADDED] app/Product/edit.erb
[ADDED] app/Product/new.erb
[ADDED] app/Product/show.erb
[ADDED] app/Product/index.bb.erb
[ADDED] app/Product/edit.bb.erb
[ADDED] app/Product/new.bb.erb
[ADDED] app/Product/show.bb.erb
[ADDED] app/Product/product_controller.rb
[ADDED] app/Product/product.rb
[ADDED] app/test/product_spec.rb

Rhodes view(ビュー)の編集

見た目を合わせるようにHTMLをカスタマイズするために、生成されたERBを編集することができます。一般的には、model(モデル)のindexページへのリンクをホーム画面に配置します。以下はStore Managerアプリ用に生成されたトップレベルのindex.erbファイルです。

<div id="pageTitle">
<h1>Storemanager</h1>

</div>

<div id="toolbar">
<div id="leftItem" class="blueButton">
<%= link_to "Sync", :controller => :Settings, :action => :do_sync %>

</div>
<% if SyncEngine::logged_in > 0 %>
<div id="rightItem" class="regularButton">
<%= link_to "Logout", :controller => :Settings, :action => :logout %>

</div>
<% else %>
<div id="rightItem" class="regularButton">
<%= link_to "Login", :controller => :Settings, :action => :login %>

</div>
<% end %>
</div>

<div id="content">
<ul>
<li>

<a href="#">
<span class="title">Add Links Here...</span>
<span class="disclosure_indicator"></span>
</a>

</li>
</ul>
</div>

Productのmodel(モデル)のインデックスページとテンプレートへのリンクを配置するため、"Add links here"のtitleがあるリスト・アイテムを以下で置き換えます:

<li>
<a href="Product">

<span class="title">Products</span>
<span class="disclosure_indicator"></span>
</a>
</li>

20100512 - grk9ymqwj66jypdckthmm5484n.png

この最上位レベルのページや他のページを、任意のHTMLで編集することができます。ここではHTMLやRubyを教えることはしませんが、たくさんの良い文献があります。

2 Rhodesでさらに行うこと

Rhodesの開発にRhoHubホスト・サービスを使ったより長いチュートリアルがあります。Technical FAQはRhodesにおいて個々のタスクを行う方法が記述されています。次のセクションでは、アプリとRhoSyncでデータを同期する仕組みを追加する方法について説明します。

RhoSyncとアプリケーションとのデータを同期の追加

RhoSyncは同期フレームワークです。デバイスのクライアント・コンポーネントとRubyが動作することができるサーバで動くサーバ・コンポーネントから構成します。RhoSyncでは、エンタープライズのバックエンドのquery(クエリ)、create(作成)、update(更新)、およびdelete(削除)の少量のコードを書くことが要求されます。これらの操作のためのRubyのコードの集まりを、"source(ソース)"または"source adapter(ソースアダプタ)"といいます。

RhoSync依存関係をインストール

RhoSync 2.0をインストールしてください



rhosync app storemanager-server
cd storemanager-server/

LinuxまたはMac上で最初に実行する場合、dtachをインストールする必要があります:


sudo rake dtach:install

インストールの確認

そしてredisとrhosyncサーバーを実行することができます:


rake redis:start
rake rhosync:start

すべてがうまくいけば、次のような表示が見えるでしょう:



[07:01:15 PM 2010-05-04] Rhosync Server v2.0.0.beta1 started...

注意:config.ruのsession secretを編集するように求められるでしょう

RhoSync source adapterの定義

一度RhoSyncをインストールしたら、バックエンド・アプリケーションと統合するRhoSync sourceをbuild(生成)する準備ができたことになります。RhoSync sourceを定義するため、バックエンドのデータソースと対話する一握りの操作:login(ログイン)、query(クエリ)、sync(同期)、create(作成)、update(更新)、delete(削除)、logoff(ログオフ)を特定する必要があります。以下のコードはRhoSyncのリリース2.0(ソースからビルドする場合、これはRhoSyncのmaster branchです)に適合します。

storemanager-serverディレクトリから、product modelのsource adapterを生成します:


rhosync source product

これはproduct adapterとproduct specの2つのファイルを生成します。


Generating with source generator:
[ADDED] sources/product.rb
[ADDED] spec/sources/product_spec.rb

以下のようなファイルを見つけることができるでしょう。生成されたsource adapterは、必要なすべてのメソッドに例外が発生するコードになっています。source generatorを使用する必要がないことに注意してください。Rubyのファイルを作成して、それをlibディレクトリに置くこともできます。source adapterのクラス名は、クライアントのmodel(モデル)と一致していなければなりません。

class Product < SourceAdapter
def initialize(source,credential)
super(source,credential)
end

def login
# TODO: Login to your data source here if necessary
end

def query
# TODO: Query your backend data source and assign the records
# to a nested hash structure called @result. For example:
# @result = {
# "1"=>{"name"=>"Acme", "industry"=>"Electronics"},
# "2"=>{"name"=>"Best", "industry"=>"Software"}
# }
raise SourceAdapterException.new("Please provide some code to read records from the backend data source")
end

def sync
# Manipulate @result before it is saved, or save it
# yourself using the Rhosync::Store interface.
# By default, super is called below which simply saves @result
super
end

def create(create_hash,blob=nil)
# TODO: Create a new record in your backend data source
# If your rhodes rhom object contains image/binary data
# (has the image_uri attribute), then a blob will be provided
raise "Please provide some code to create a single record in the backend data source using the create_hash"

end

def update(update_hash)
# TODO: Update an existing record in your backend data source
raise "Please provide some code to update a single record in the backend data source using the update_hash"
end

def delete(object_id)
# TODO: write some code here if applicable
# be sure to have a hash key and value for "object"
# for now, we'll say that its OK to not have a delete operation
# raise "Please provide some code to delete a single object in the backend application using the hash values in name_value_list"
end

def logoff
# TODO: Logout from the data source if necessary
end
end

generatorはまた、settings/settings.ymlを編集し、いくつかのデフォルトのオプションでproduct adapterをsources sectionへ追加します。



#Sources
:sources:
Product:
:poll_interval: 300

次のステップはバックエンド・サービスを呼び出す独自のコードを、login(ログイン)、query(クエリ)、create(作成)、update(編集)、delete(削除)とlogoff(ログオフ)のメソッドに埋め込むことです。

以下にどのようなコードになるかを説明します。

RhoSync query(クエリ)

もしREAD-ONLYの認証なしのソースアダプタを作るのならば、ここで説明するようにレコードを取得するqueryメソッドを一つ書くだけで終わります。以下はRESTインターフェースを公開している簡単な製品カタログ(http://rhostore.heroku.com)とやり取りするqueryメソッドの見本です。RhoSyncは任意のプロトコルで動作することができます。この例は、一般的なRESTインターフェースでのJSON over HTTPです。RhoSyncソースアダプタは純粋なRubyコードで、必要なものはなんでも簡単に接続して解析することができるRubyライブラリ(別名、gems)があります。--queryコードはちょっと違います。

カタログのすべての製品を返す私たちのサンプルWebサービス( http://rhostore.heroku.com/products.json )はこのようなデータを返します:


[
{"product":
{"name": "iPhone", "brand": "Apple", "updated_at": "2010-05-11T02:04:57Z", "price": "$299.99", "quantity": "5", "id": 649, "sku": "1234", "created_at": "2010-05-11T02:04:57Z"}},
{"product":
{"name": "Accord", "brand": "Honda", "updated_at": "2010-05-13T22:24:48Z", "price": "$6000", "quantity": "", "id": 648, "sku": "123", "created_at": "2010-05-11T02:04:53Z"}}
]

データを解析する以下のRubyコードは、REST webサービスを簡単にアクセスするため、標準のRuby JSONライブラリとRestClientライブラリを使っています。この例では、ハッシュキーとしてproductレコードのidを使用します。注:このハッシュのキーはstring(文字列)でなければなりませんし、値はRubyのハッシュとして表現されるname-valueのペアの任意のセットとなります。インスタンス変数@resultはqueryメソッドによって設定されるユニークなidでインデックスされるこの"ハッシュのハッシュ"でなければなりません。それはbaseとなるSourceAdapter classのsync()メソッドがObjectValueテーブルを作成できるようにするためです。

利用する標準ライブラリをファイルの先頭で宣言する必要があります:

require 'json'
require 'rest_client'

簡単にするため、コンストラクタにwebサービスのベースURLを持つインスタンス変数@baseを追加し、その値を設定します

  def initialize(source,credential)
@base = 'http://rhostore.heroku.com/products'

super(source,credential)
end

次に、クエリメソッドの入力:

  def query
parsed=JSON.parse(RestClient.get("#{@base}.json").body)

@result={}
if parsed
parsed.each do |item|
key = item["product"]["id"].to_s
@result[key]=item["product"]
end
end
end

上のコードはもっと簡潔になるかもしてませんが、Ruby言語に慣れていないプログラマにとって読みやすく書かれています。Rubyに始めたばかりの場合は、良い手引きがその他の言語からRuby読むことができます。

RhoSync Sync(同期)メソッド

syncコードはクエリの結果をばらばらにしてobject_valuesテーブルに格納します。ObjectValueオブジェクトを作成し、source_idとuser_id属性と共にそのオブジェクト・属性・値の属性を設定することができる独自のコードを書くことができます。しかし、@resultにハッシュのハッシュを設定すると、この作業を避けることができます。syncメソッドをこのようにするだけです:

def sync
super
end

上記のメソッドはデフォルトで生成されるメソッドで、もう何もする必要はありません。

queryメソッドで処理を分割する方法もあります。@resultに設定せずsyncメソッドがハッシュのハッシュを設定する方法です。このハッシュのハッシュは(上記のqueyメソッドで説明したように)外側のハッシュのキーがそれぞれのオブジェクトのIDとなるハッシュです。内部ハッシュの各ハッシュキーは、個々のオブジェクトの属性を表します。注意しなければならないのは、すべてのデータ型は文字列(string)でなければなりません。(よって、ハッシュ値は、すべて整数ではなく文字列である必要があります。たとえば、以下のようになります。

  @result={"1"=>{"name"=>"inner tube","brand"=>"Michelin"},"2"=>{"name"=>"tire","brand"=>"Michelin"}}

クライアントからの同期テスト

redisを実行していることを確認して、サーバーを起動(または再起動)してください:

  rake rhosync:start

サーバーが起動すると、ソースアダプタのコードがロードされます。Rubyコードで構文エラーがある場合は、その旨が表示されサーバーは起動しません。ランタイムエラーがある場合は、ソースアダプタが呼ばれるまでそのエラーは表示されません。

このサーバーのURLがアプリケーションに設定されていることを確認してください。サーバーがデフォルトのポートでlocalhost上で実行されている場合、次の行をrhoconfig.txtの下部に設定する必要があります:

syncserver ='http://localhost:9292/application'

storemanager/app/Product/product.rbのmodel(モデル)でsync(同期)を有効にします。

class Product
include Rhom::PropertyBag

enable :sync
end

起こっていることの感触をつかむためには、ターミナル・ウィンドウでサーバーのログ(rake rhosync;startの出力)と別のウィンドウでクライアントログのtail(末尾)を見ることです。たとえば、iPhone上でクライアントのログの末尾を表示するには:

  tail -f rholog-User.txt

サーバーと同期するには、クライアントはログインする必要があります。生成されたアプリにはログインとその他一般的な機能のための画面があります。これらは、一般的にアプリのデザインに合うように変更します。重要だけどありきたりなユーザー認証や設定を実装する前に、アプリケーションのコア機能に焦点を当てることができるので、この生成されたUIは便利でしょう。

  1. 画面の下部にある歯車のアイコンをクリックして設定画面に移動します
  2. 任意の名前とパスワードでログインします。生成されたコードはどんなログインでも許可しますが、application.rbで変更することができます。
  3. ログインが成功した場合は、設定画面でClientIDが表示されます。ClientIDは、あなたが初めてログインしたときに生成され、クライアントのデータベースに格納されます。それはrhosyncに必要な一意の識別子として機能します。(注:この値はログインをまたいで保持されますが、クライアントのデータベースをリセットしたりアプリを再インストールした場合、新しいClientIDが生成されます)
  4. sync(同期)は自動的にトリガされます。homeアイコンをクリックし"Products"を選択すると、サーバーからのレコードを見ることができるでしょう。

RhoSyncでオブジェクトの作成

create(作成)メソッドには、RhoSyncサーバーが"new_object_hash"という新しいレコードを含むハッシュを渡すと考えてください。例えば、それは次のようなものです:

{"name"=>"sku","value"=>"1", "name"=>"name", "value"=>"inner tube"}

create(作成)メソッドは、最後のsync(同期)以降クライアントで作成されたすべてのオブジェクトに対して一度ずつcallされます。createするコード(またはeditやdeleteも)は動作するために、この設定された配列を使用する必要があります。以下は、HTTP POSTを受け付けるhttp://heroku.com/rhostoreに対するcreateメソッドの一例です。createメソッドは、後々クライアントで変更可能なオブジェクトの一意のID string(文字列)を返す必要があります。もしidが返されない場合は、クライアント・オブジェクトをREAD-ONLY(読み取り専用)と取り扱うべきでしょう。なぜなら、そのオブジェクトはsync(同期)できないからです。

def create(new_object_hash, blob=nil)
result = RestClient.post(@base,:product => new_object_hash)

# after create we are redirected to the new record.
# The URL of the new record is given in the location header
location = "#{result.headers[:location]}.json"


# We need to get the id of that record and return it as part of create
# so rhosync can establish a link from its temporary object on the
# client to this newly created object on the server

new_record = RestClient.get(location).body
JSON.parse(new_record)["product"]["id"].to_s
end

コードを変更した後、ソースアダプタをリロードするために、rhosyncを再起動する必要があります。オブジェクトはクライアント上ですぐに作成されますが、サーバーに送信されるのは次回のsync(同期)時であることに注意してください。設定画面の"Perform Sync"をクリックすると、すぐにサーバーコードをテストすることができますが、通常の同期は5分ごとに発生します。

認証

生成されたアプリケーションコードには、認証をフックする"application.rb"ファイルがディレクトリのルートにあります。完全なファイルは次のようになります:

class Application < Rhosync::Base
class << self
def authenticate(username,password,session)
true # do some interesting authentication here...
end

# Add hooks for application startup here
# Don't forget to call super at the end!
def initializer(path)
super
end

# Calling super here returns rack tempfile path:
# i.e. /var/folders/J4/J4wGJ-r6H7S313GEZ-Xx5E+++TI
# Note: This tempfile is removed when server stops or crashes...
# See http://rack.rubyforge.org/doc/Multipart.html for more info
#
# Override this by creating a copy of the file somewhere
# and returning the path to that file (then don't call super!):
# i.e. /mnt/myimages/soccer.png
def store_blob(blob)
super #=> returns blob[:tempfile]
end
end
end

Application.initializer(ROOT_PATH)

バックエンドのWebサービスが認証を必要とする場合は、単にauthenticateメソッドにコードを追加して、認証が成功したらtrueを返し、クライアントからのアクセスの認証が失敗したらfalseを返すようにしてください。たとえば、

    def authenticate(username, password, session)
[... connect to backend using API and authenticate... ]
if success
# we store these in the session encrypted
session[:someprivatedata] = someprivatedata
end
return success
end

詳細情報

RhoSync 2.0 :新しいRhoSync 2.0のマニュアル。RhoSync 2.0の違いと新しく追加された機能について

APIのサンプル :このRhodesアプリケーションは、個々のRhodes機能を紹介するコードが書かれています。

このような本もありますbook on Rhomobile。さらなるご質問については、 私たちへメールRhomobile Google Groupへ参加してpostしてください。


0 件のコメント: