公式なドキュメントはRhomobile社のサイトをご覧ください。
また、この文書は2010/6/16(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/16 (JST) information.
If you have any question, problem about the Japanese translation, please leave your comment. Except for that, refer contacts in the document.
はじめに
RhomはRhodesのミニORM(オブジェクトリレーショナルマッパー)です。これは、プログラムにローカルデータベースを簡単に作成する高レベルの方法を提供します。そのデータベースは、HSQLのBlackBerryを除いては、すべてのプラットフォームでSQLiteです。
Property Bags
すべての処理は1つのテーブル上で実行されるので、Rhomはそれぞれのソースidでプロパティのセットを決定できます。次の例では、この考えを示しています:
Source ID: 1, Model name: Account
+-----------+----------+--------------------------------------+-------------------------------------+-------------+
| source_id | attrib | object | value | update_type |
+-----------+----------+--------------------------------------+-------------------------------------+-------------+
| 1 | name | 3560c0a0-ef58-2f40-68a5-48f39f63741b | A.G. Parr PLC 37862 | query |
| 1 | industry | 3560c0a0-ef58-2f40-68a5-48f39f63741b | Entertainment | query |
| 1 | name | db780956-f03b-c819-b84f-48f39f230529 | A.G. Parr PLC 387027 | query |
| 1 | industry | db780956-f03b-c819-b84f-48f39f230529 | Entertainment | query |
+-----------+----------+--------------------------------------+-------------------------------------+-------------+
この例では、Rhomは2つのユニークなattribute("name"と"industry")と以下のクラスを作成し、object、update_typeとsource_idを追加のarrtibuteとして集めます:
class Account < RhomObject
attr_accessor :name,
:industry,
:object,
:source_id,
:update_type
end
メソッド
ask(question)
rhosyncへ提供されるquestionで、非同期ask requestを行います。そのquestionは関連したrhosyncアダプタに処理のために渡され、その結果はrhom objectとしてクライアントに返されます。結果を素早く取得し、ビューを更新するために、set_notification / clear_notificationの一連を使用することができます。
CuriousCustomer.ask("What is Rhodes?")
clear_notification
オブジェクトの通知をクリアするのに使用します。詳細はSync Notification Docsを参照してください。
delete_all(conditions)
すべてのrhomオジェクトをソースから削除します。conditionsによってフィルタリングもできます。:
:conditions # delete only objects matching these criteria
Account.delete_all(:conditions => {'industry'=>'electronics'})
destroy
現在のrhomオブジェクトを削除します。
@account = Account.find(:all).first
@account.destroy
find(*args)
次の引数に基づいたrhomオブジェクトを返します:
:all # returns all objects w/ optional conditions
:first # returns first object matching conditions
:count # returns number of objects matching conditions
:conditions #(optional) hash of attribute/values to match with (i.e. {'name' => 'ABC Inc.'})
# SINCE 1.2 - supports sql fragment (i.e. "name like 'rhomobile') or sql fragment with binding (i.e. ["name like ?", company])
# DO NOT USE sql fragment, use advanced queries instead(see next section). Sql fragment queries will work SLOW on all platforms
:order #(optional) attribute to order the list
:orderdir #(optional) order direction ('ASC' - default, 'DESC' )
:select #(optional) array of strings representing attributes to return with the object.
#NOTE: use it only if model has a lot of attributes, but you need few of them. This is performance only field.
:per_page #(optional) maximum number of items return
:offset #(optional) offset from beginning of the list
ブロックにカスタム・オーダーをを提供するためのfindは:$foundContacts = Contact.find(:all,
... ){ |a,b| a.to_i <=> b.to_i }
acct = Account.find "3560c0a0-ef58-2f40-68a5-48f39f63741b"
acct.name #=> "A.G. Parr PLC 37862"
accts = Account.find(:all, :select => ['name','address'])
accts[0].name #=> "A.G. Parr PLC 37862"
accts[0].telephone #=> nil
より最適化されたいくつかのオブジェクトの存在を確認したい場合は、:firstを使います。
find_all(*args)
find(:all,*args) の別名です。
find(*args) Advanced proposal
SQLのようなハッシュ条件を作成したいとすると:
find( :all,
:conditions =>["LOWER(description) like ? or LOWER(title) like ?", query, query],
:select => ['title','description'] )
これは、以下のようにすることができます:
find( :all,
:conditions => { {:func=>'LOWER', :name=>'description', :op=>'LIKE'}=>query,
{:func=>'LOWER', :name=>'title', :op=>'LIKE'}=>query}, :op => 'OR',
:select => ['title','description'])
IN operationの例は:
find(:all, :conditions=>{
{:name=>"image_uri", :op=>"IN"} => "\"15704\",\"15386\""
} )
グループ条件も可能です:
cond1 = {
:conditions => {
{:func=>'UPPER', :name=>'name', :op=>'LIKE'} => query,
{:func=>'UPPER', :name=>'industry', :op=>'LIKE'} => query},
:op => 'OR'
}
cond2 = {
:conditions => {
{:name=>'description', :op=>'LIKE'} => 'Hello%'}
}
@accts = Account.find( :all,
:conditions => [cond1, cond2],
:op => 'AND',
:select => ['name','industry'])
最終的に(代わりにハッシュの配列を条件にすることを提案します - 1.4では未サポート):
find( :all,
:conditions => [{:func=>'LOWER', :name=>'description', :op=>'LIKE', :param=>query},
{:func=>'LOWER', :name=>'title', :op=>'LIKE', :param=>query}],
:op => 'OR',
:select => ['title','description'])
new(attributes)
提供されるattributeに基づいて新しいrhomオブジェクトを作成したり、オブジェクトを空で初期化します。
@account = Account.new({'name'=>'ABC Inc.','address'=>'555 5th St.'})
@account.name #=> "ABC Inc."
paginate(*args) (1.2以降)
制限された数のレコードを返すfindをコールします。railsの古いpaginationのエミュレートです。デフォルトページサイズは10です。
Account.paginate(:page => 0) #=> returns first 10 records
Account.paginate(:page => 1, :per_page => 20) #=> returns records 21-40
Account.paginate(:page => 5, :conditions => {'industry' => 'Technology'}, :order => 'name') #=> you can mix conditions & order as well
引数:
:page # which page to return (used as offset in combination with :per_page)
:per_page # number of records to return (used as limit)
:conditions # see definition in find
:order # see definition in find
:select # see definition in find
保存
現在のrhomオブジェクトをデータベースに保存します。
vars = {"name"=>"some new record", "industry"=>"electronics"}
@account = Account.new(vars)
@account.save
sync(callback=nil, callback_data="", show_status_popup=nil)
指定されたモデルの同期プロセスを開始する要求。コールバックがnilではない場合は、SyncEngine.set_notificationが同期の前に呼び出されます。
set_notification(URL)
ページを非同期refreshするために使います。より詳細は、Sync Notification Docs参照してください。
update_attributes(attributes)
現在のrhomオブジェクトの属性を更新し、それをデータベースに保存します。
new_attributes = {"name"=>"ABC Inc.", "industry"=>"Technology"}
@account = Account.find(:all, :conditions=>{'name'=>'ABC Inc.'})
@account.update_attributes(new_attributes)
@account.industry #=> "Technology"
can_modify
アイテムを変更するページを表示する前に、アプリケーションはそのアイテムが変更が可能かどうかをチェックすべきでしょう。アイテムが中間状態になることがあります:データはサーバーへ送信されたが、サーバーからの応答を受信していない状態。
def edit
@product = Product.find(@params['id'])
if @product && !@product.can_modify
render :action => :show_edit_error
else
render :action => :edit
end
end
changed?
サーバーへ同期されなければならないローカルでの変更がモデルにあったかどうかを検出します。
def should_sync_product
Product.changed?
end
def should_sync_product_object
@product = Product.find(@params['id'])
if @product.changed?
#... do stuff ...
end
end
RhoSyncを使用しないモデルの使用
- クライアント上のローカルなデータベースにデータを格納するモデルを使うこともできます。手動もしくはrhogenを使って、必要なモデルを追加するだけです。
- Rhodes2.0以降、同期はデフォルトで無効になります。
- config.rbで空の同期のURLを設定します:
Rho::RhoConfig::add_source("Customer", {"url"=>''})
- rhoconfig.txtでバックグラウンド同期を無効にします:sync_poll_interval = 0
Rhomモデル
2種類のモデルがあります - 'property bag'モデルと'fixed schema'モデルです
- property bagは、オブジェクトのid,attribute,valueの3つを持つdbのテーブルです。よって、それぞれのオブジェクトのattributeの集まりは任意です。
- fixed schemaは、カラム(attribute)の固定した集合の一般的なdbテーブルです。
- モデルファイル名はクラス名であり、小文字とそれぞれの大文字の後の_からなります:Product\product.rb,IM\i_m.rb
Property Bag Model
class SomeModel
include Rhom::PropertyBag
# rhosync settings
enable :sync #default is disabled - for local models
# you may use set :sync, true instead
set :sync_type, :bulk_only #default is :incremental (which allow for bulk and regular sync)
set :sync_priority, 1 #1000 by default, first will sync models with 0, then 1 etc
# model settings
set :partition, :app #default user
# object properties
# any object may have arbitrary set of properties
# blob fields called out explicitly to identify field type
# :blob - declare property as a blob type
# :overwrite - (optional) overwrite client copy of blob with new copy from server
# useful when server modifies images, for example zooming or cropping
property :image_url, :blob, :overwrite
end
Fixed Schema Model
class SomeModel
include Rhom::FixedSchema
# rhosync settings
enable :sync #default is disabled - for local models
# you may use set :sync, true instead
set :sync_type, :bulk_only #default is :incremental (which allow for bulk and regular sync)
set :sync_priority, 1 #1000 by default, first will sync models with 0, then 1 etc
# model settings
set :partition, :app #default :user
set :schema_version, '1.0' #application may use it for data migration
# object properties
property :name, :string
property :tag, :string
property :phone, :string
property :image_url, :blob
# blob fields called out explicitly to identify field type
# :blob - declare property as a blob type
# :overwrite - (optional) overwrite client copy of blob with new copy from server
# useful when server modifies images, for example zooming or cropping
property :cropped_image_url, :blob, :overwrite
# object column will be added by rhom and will be primary key
#indexes
index :by_name_tag, [:name, :tag] #will create index for name and tag columns
unique_index :by_phone, [:phone] #will create unique index for phone column
end
associations
class Customer
include Rhom::PropertyBag
belongs_to :product_id, 'Product'
end
#product_controller.rb create code:
def create
@product = Product.new(@params['product'])
@product.save
cust = Customer.find(:first) #find customer
cust.product_id = @product.object
cust.save
redirect :action => :index
end
同期した後に、新しいProductのオブジェクトidが更新されます。注意:このシナリオで正しく動作するためには、ProductはCustomerの前に同期されなければなりません。したがって、Customerが'sync priority=1'ならばProductは0でなければなりません。
例
RhoSyncなしのモデル:
class SomeModel
include Rhom::PropertyBag
end
RhoSync対象のシンプルなモデル:
class SomeModel
include Rhom::PropertyBag
enable :sync
end
Source Configuration Protocol
RhoSyncは、クライアント・サーバプロトコルを介して以下のjsonの形でsource configurationを送信します。
{
"sources": {
"Product": {
"partition": "application",
"schema": {
"property": {
"brand": "string",
"price": "string",
"name": "string",
"image_url": "blob,overwrite"
},
"unique_index": {
"by_price": "price"
},
"version": "1.0",
"index": {
"by_brand": "brand",
"by_name_brand": "name,brand"
}
},
"poll_interval": 300,
"sync_type": "incremental",
"belongs_to": {
"brand": "Customer"
},
"sync_priority": 0
}
}
}
これは、以下のyml定義から翻訳されます:
sources:
Product:
poll_interval: 300
sync_priority: 0
partition: 'application'
schema:
version: '1.0'
property:
name: 'string'
price: 'string'
brand: 'string'
image_url: 'blob,overwrite'
index:
by_name_brand: 'name,brand'
by_brand: 'brand'
unique_index:
by_price: 'price'
sync_type: 'incremental'
belongs_to:
brand: 'Customer'
データの移行
Property Bag model
Property Bag modelを使うとき、スキーマの変更(attributeの追加や削除)を追跡する必要はありません。 しかしながら、Rhodesはsqlデーターベースにアプリデータを格納するために、property bagスキーマを使用します。internal property bagスキーマが変わった場合、アプリケーションが更新・リロードされた後、dbは(再)作成され、存在していたすべてのデータは消されてなくなります。internal dbスキーマ・バージョンについては、rhodes\lib\rhodes.rb と rhodes\lib\framework\rhodes.rb を見てください。
DBVERSION = '2.0.3'
アプリケーションが初めてインストールされたあとに最初にアプリケーションが起動したときや、rhoconfig.txtのapp_db_versionが上記と異なるならば、更新・再ロードされたデータベースは(再)作成されます。データベースのバージョンが変更され、データベースが再作成された場合、そのデータベースのデータは消えてなくなります。
rhoconfig.txtのアプリケーションデータベースのバージョン:
app_db_version = '1.0'
Fixed Schema Model
Fixed Schema Modelアプリケーションを使用する場合、開発者はsqlスキーマに責任があります。したがって、propertyの追加や削除やアプリのロジックを変更するときには、データのmigrationやデータベースのリセットを行う必要があります。スキーマの変更を追跡するためにモデルのschema_versionパラメータを使用します:
class Product
include Rhom::FixedSchema
set :schema_version, '1.1'
end
class AppApplication < Rho::RhoApplication
# this method called when schema_version parameter has been changed in 2 cases:
# at application start
# when server send sources to client
# old_version is String containing old version value
# new_src is Hash with source parameters like 'schema_version', 'name' etc; new_src['schema']['sql'] contain sql table creation script
def on_migrate_source(old_version, new_src)
# call super to delete table
# return false to run sql script to create table with new schema
end
end
Sync Sources
Rhodes sync sourcesはRhomSourceオブジェクトを介してRhodes Rubyフレームワークで利用可能です。source_urlフィールドだけが書き込み可能な普通のRhomオブジェクトのようにRhomSourceを使うことができます。(以下は、RhomSourceの使い方を説明するサンプル・アプリケーションに提供されるSourceControllerです)
require 'rho/rhocontroller'
require 'rhom/rhom_source'
class SourceController < Rho::RhoController
include Rhom
def index
@sources = RhomSource.find(:all)
render :action => :index
end
def edit
@source = RhomSource.find(@params['id'])
render :action => :edit
end
def update
@source = RhomSource.find(@params['source']['source_id'])
@source.update_attributes(@params['source'])
redirect :action => :index
end
end
また、RhomSourceにある以下のattributeにアクセスすることができます:
@source = RhomSource.find(@params['id'])
puts @source.source_id #id of source
puts @source.name #name of source
puts @source.source_url #url of a source
puts @source.last_updated #returns Time object of last sync for the source (in Time.at format)
puts @source.last_inserted_size #returns number of records inserted on last sync
puts @source.last_deleted_size #returns number of records deleted on last sync
puts @source.last_sync_duration #returns duration of last sync for this source in seconds
puts @source.last_sync_success #returns 1 if sync was successful, 0 otherwise
puts @source.distinct_object #returns number of records
Product sourceの最後の同期時刻を表示する例:
<%= ::Rhom::RhomSource.find(Product.get_source_id).last_updated.strftime("%m/%d/%Y, %I:%M%p") %>
データベースクラッシュリカバリ
Rhodesは、不良または破損状態からデータベースを回復するための以下の機能を提供しています。
Rhom::Rhom.database_full_reset #deletes all records from object_values table and client_info table
0 件のコメント:
コメントを投稿