Permalink
Switch branches/tags
Find file
Fetching contributors…
Cannot retrieve contributors at this time
289 lines (210 sloc) 12.8 KB
# Rhodes Application
## App structure
The Rhodes application generator generates a basic application from the "rhodes app" option. It will generate subdirectories and controller and template files when specifying a model and actions. Please refer to the [Rhodes generator](generator) documentation for more detailed information about the Rhodes directory structure.
### Example Directory Structure
As an example, /sugar could be the root folder for an application that provides mobile access to SugarCRM. The app's root directory will contain a few .erb files, depending on the app's functionality. At the very least there will be an index.erb file that serves as the default landing page. This default landing page will typically have links to the controllers for some of the data models, and is not associated with any specific controller. In case the application needs a default landing page associated with a controller, it is recommended to create a model/controller/view folder and use an action on this controller as a default start path. To do that, edit the start_path property in the [Configuration]() framework configuration file.
## Model/View/Controller
By convention, files for each Model include a controller, a model class and view templates described below.
### Controller
Developer may create any number of controller actions by simple defining new methods in the controller class. Each action associated with url and can be performed by calling that url from the View in the WebView control. WebView control is a Web Browser imbedded in the application UI.
For example, if you have Account Model your controller actions will be in account_controller.rb file. To defined action 'list' you will create method 'list' in the account_controller.rb file:
:::ruby
def list
#implement required business logic here
#...
#return result to the browser
render :action => :list
end
From the View list action will be available as 'Account/list' url.
Each generated model controller has several actions to perform basic CRUD (create, read, update and delete) on the object. These actions are:
* index - lists all objects
* new - displays the editing form for creating a new object
* create - actually creates the object
* edit - edits an existing object
* update - updates properties of the object
* show - views the object
* delete - deletes the object
Generated set of actions (and the associated URL paths) follows the Rails scaffolding pattern for creating CRUD actions for objects and the associated "map resources" convention for routing to those actions.
### Model
To store data locally Rhodes uses Sqlite on iPhone, Android, and Windows Mobile. On Blackberry version up to 5.0 Rhodes uses Hsql. On version 5.0 and higher it is possible to use Sqlite or Hsql. To access and manipulate stored data you may use [Rhom](rhom). Rhom is a mini ORM (object relational mapper) for Rhodes. It provides a high level way to make the local database easier to program to.
By convention, your model class is located in the model's folder. For the model "UserBase" the file would be called "user_base.rb"
Example of added upper_name method to the model:
:::ruby
class UserBase
include Rhom::PropertyBag
#add model specific code here
def upper_name
self.name.upcase
end
end
You may define PropertyBag model or FixedSchema models. In first case model object may have any number of attributes and developer may create them on the fly by assigning values to an attribute. Fixed schema is more rigid and attributes of such objects should be defined at compile time. But Fixed Schema objects will require significantly less space on the target device. See more details about Rhom [here](rhom).
### Views (Templates)
Each controller action usually associated with a View template. The .erb files mentioned above are the templates used for views. Rhodes follows the Rails convention for template naming.
* index.erb - lists the data model objects
* edit.erb - lets you edit the object
* show.erb - shows the object's attribute values
* new.erb - creates a new object
These files are all created by the [rhodes generator](generator). Inside the template, any valid HTML, JavaScript, and Ruby can be used, with Ruby code enclosed in <% and %> tags. See more information about ERB [here](http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/).
To send View to the browser, use render method in your controller. For example, to render list.erb, make following call in your controller:
:::ruby
render :action => :list
Rhodes framework will load list.erb template, process it, and send resulted HTML to the browser.
## AppApplication class
To coordinate application startup Rhodes framework introduced Application class. This class persistent all the time while app is running and across all requests to the controller actions. You can store session data here. To get an instance of the AppApplication object in your controller, use:
:::ruby
::Rho.get_app
AppAplication class defined in the application.rb file:
:::ruby
class AppApplication < Rho::RhoApplication
def initialize
# put initialization code here
end
end
You may listen for activation/deactivation/upgrade events if you define following methods on AppApplication class.
Method on_ui_created will be invoked after application's UI was created (usually on app start)
:::ruby
def on_ui_created
# put your application UI creation code here
# for example, create tab bar:
# NativeBar.create(Rho::RhoApplication::TABBAR_TYPE, tabs)
super # To navigate to start_path from rhoconfig.txt
end
Method on_ui_destroyed will be invoked when application's UI was destroyed (usually on app exit)
:::ruby
def on_ui_destroyed
# put your code here
# example:
# @forbid_ui_operations = true
end
**NOTE: On iPhone, on_ui_destroyed invoked when also when application goes to background, because if application killed in background by user (via multitasking UI) then no any events sended to application. So if you want save state of your application, you can do it in on_ui_destoyed, but keep in mind - is just save - do not process destroy of your UI in this method**
Method on_activate_app will be invoked after application is activated.
:::ruby
def on_activate_app
# put your application activation code here
end
Method on_deactivate_app will be invoked before application goes to background.
:::ruby
def on_deactivate_app
# Don't call any UI operations here, they'll be ignored
# For example, WebView.refresh
# to stop sync background thread call
# SyncEngine.stop_sync; SyncEngine.set_pollinterval(0)
# To stop local web server when application switched to
# background return "stop_local_server"
# return "stop_local_server"
end
Method on_reinstall_config_update may be called after application was upgraded. If application bundle contain rhoconfig with properties modified locally on the phone conflicts is a hash name to array of conflicted values(old local value, new upgrade value). By default local values are kept in place but you may overwrite configuration with new values and any other steps required for your application upgrade.
:::ruby
def on_reinstall_config_update(conflicts)
# puts "on_reinstall_config_update: #{conflicts}"
end
### Relative order of callbacks and conditions where they occurs
Look to the scheme of application life cycle:
initialize -> called when application start
on_ui_created -> called when application's UI created
on_activate_app -> called when application become foreground
Now application is live and visible on the screen. Assume now that user somehow
switched to another application (for example, answering to incoming call) or
explicitly send app to background.
on_deactivate_app -> called when application switched to background
Now, on this stage, application can be activated again (in this case *on_activate_app*
will be called) or system can destroy it's UI to free some memory (in this case
*on_ui_destroyed* will be called).
Let's look on case if app's UI was destroyed but then we activated app again:
on_ui_destroyed -> called when OS destroy app's UI
on_ui_created -> called just after user request system activate
app (for example, tap app's icon on screen)
on_activate_app -> called when app goes to foreground
Ok, now user choose to exit from app completely (either by selecting menu item
"Close" or calling System.exit method somewhere in app code).
Let's look on callbacks chain in this case:
on_deactivate_app -> at first, app will be deactivated (become
invisible on screen)
on_ui_destroyed -> then, app's UI will be destroyed
Kernel.at_exit -> all calls registered by calling of
Kernel.at_exit will be called as in usual Ruby.
That's how it's working. Important thing to understand is that *on_activate_app* callback
always called **after** *on_ui_created* and *on_deactivate_app* always called **before** *on_ui_destroyed*
## Application Helpers
Few helper methods defined as part of the Rhodes framework. There are just a few of them because Rhodes framework designed for mobile environment where size is still of some concern and we tried to keep framework as tight as possible.
Generated application comes with number of other helpers (see app/helpers folder). These helpers are not used by the framework internally and may be modified/deleted/extended at will.
### link_to
Examples of how to use the link_to method:
link_to "Visit Other Site", "http://www.rhomobile.com/"
==> <a href="http://www.rhomobile.com/" >Visit Other Site</a>
link_to "Help", { :action => "help" }
==> <a href="/app/model/help" >Help</a>
link_to "Delete", { :action => "delete", :id => '{12}' }
==> <a href="/app/model/{12}/delete" onclick="
var f = document.createElement('form');
f.style.display = 'none'; this.parentNode.appendChild(f);
f.method = 'POST'; f.action = this.href; f.submit();
return false;">Delete</a>
link_to "Show", { :action => "show", :id => '{12}'},
"style=\"height:4px;width:7px;border-width:0px;\""
==> <a href="/app/model/{12}/show"
style="height:4px;width:7px;border-width:0px;">Show</a>
link_to "Delete", { :action => "delete", :id => '{12}' },
"class=\"delete_link\""
==> <a href="/app/model/{12}/delete" class="delete_link"
onclick="var f = document.createElement('form');
f.style.display = 'none'; this.parentNode.appendChild(f);
f.method = 'POST'; f.action = this.href; f.submit();
return false;\">Delete</a>"
link_to "Invite",:action => :invite,
:query => {:name=>'John Smith','address'=>"http://john.smith.com"}
==> <a href="/app/model/invite?
name=John%20Smith&address=http%3A%2F%2Fjohn.smith.com">
Invite</a>
### url_for
Examples of how to use the url_for method:
url_for '/some_url'
==> /some_url
When generating a new URL, missing values may be filled in from the current request's parameters.
For example, if the application name or model are not specified in the call parameters, they would be filled from the request.
url_for :action => :index
==> /app/model
url_for :action => :create
==> /app/model
url_for :action => :new
==> /app/model/new
url_for :action => :show, :id => '{12}'
==> /app/model/{12}/show
url_for :model => :another_model,
:action => :show, :id => '{12}'
==> /app/another_model/{12}/show
url_for :controller => :another_controller,
:action => :show, :id => '{12}'
==> /app/another_controller/{12}/show
url_for :application => :another_app,
:model => :another_model, :action => :show, :id => '{12}'
==> /another_app/another_model/{12}/show
url_for :action => :create, :query =>
{:name => 'John Smith', 'address' => "http://john.smith.com"}
==> /app/model?name=John%20Smith&address=http%3A%2F%2Fjohn.smith.com
url_for :action => :show, :id => '{12}', :fragment => "an-anchor"
==> /app/model/{12}/show#an-anchor
## Error handlers(400,500)
Rhodes can display the following error pages: app\E400.erb and app\E500.erb
* error 400 occurs when there's a Rho::RecordNotFound exception (for example, when you search for a non-existent objectID)
* error 500 occurs for any other unhanded exception
To get exception object use $! or Rho::RHO.current_exception
## RhoSupport class
### Rho::RhoSupport.url_encode(url)
Encode url replacing special characters to %XX
### Rho::RhoSupport.url_decode(url)
Decode url replacing %XX to special characters
## Per Platform Files
On a per platform basis, you can use alternative files for any given file in your 'app' or 'public' folder. To do this, make a second file with the platform in the name of the file.
For example, to replace these files on the Android platform:
default.css
index.erb
All you need to do is add the two files:
default.android.css
index.android.erb
Note that you must still have the base file present for it to be replaced on a platform.
Valid platform names are:
* android
* wm
* bb
* iphone