来源: http://webddj.sys-con.com/read/295396.htm
相关链接:
With the release of Flex 2, Adobe has introduced a tool that makes building rich user interfaces for the Web easier than ever; of course, as anyone remotely plugged in to the Web development community knows, Ruby on Rails has made creating database-driven Web applications brain dead simple. This article discusses a technology that marries Flex with RoR applications by providing a means of automating the communication between the client and server. The technology is "WebORB for Rails," a free and open source (GPL) server made available by Midnight Coders ( www.themidnightcoders.com ).
Many of the tutorials on the Web that talk about integrating Flex clients with Rails discuss using raw XML over HTTP. While this mechanism is nice for the standard "mom and apple pie" tutorial that return a simple list of records, this level of integration quickly becomes unwieldy as the complexity of the application grows. With each new operation on the server, a developer must spend valuable cycles serializing and deserializing requests and responses before they can focus on the actual business logic.
WebORB relieves the burden of this "serialization tax" by supporting the concept of remote objects whereby Flex clients can natively invoke methods on the server and retrieve the responses all within ActionScript, the object-oriented programming language used by Flex.
This article will discuss installing WebORB to "Flex-enable" a Ruby on Rails application, the steps required to create an application using Flex + WebORB + RoR, and some advanced topics like dealing with Rails models, etc.
Installing WebORB for Rails
WebORB runs as a plug-in for Rails and is installed by simply running the following command within the root directory of a Rails application. On *nix systems:
./script/plugin install http://themidnightcoders.net:8089/svn/weborb/
or on Windows:
ruby script/plugin install
http://themidnightcoders.net:8089/svn/weborb/
Writing an Application Using WebORB
There are three simple steps that are required to build a Flex-based RIA utilizing WebORB and Rails.
- Build the service class and drop into RAILS_APP/app/services
- Add an entry to RAILS_APP/config/WEB-INF/flex/remoting-config.xml for the remote service
- Set up a RemoteObject on the client-side using Flex that will communicate directly with the back-end service.
As a simple example consider the following service written in Ruby:
require 'weborb/context'
require 'rbconfig'
class InfoService
def getComputerInfo( requestId )
computer_info = Hash.new
request = RequestContext.get_request
computer_info['serverName'] = request.server_software
computer_info['requestId'] = requestId
computer_info['os'] = Config::CONFIG["arch"].to_s
computer_info['currentTime'] = Time.now
computer_info
end
end
This example is bundled within the WebORB on Rails product and simply returns a bag of properties related to the server running the service. Generally, the classes that are surfaced as remote objects are added to a /services directory under the RAILS_APP/app directory.
After creating this class, you must also tell Flex that this class needs to be available as a remote object. This is configured by adding the following snippet of XML to the remoting-config.xml file located within the RAILS_APP/config/WEB-INF/flex directory:
<destination id="InfoService">
<properties>
<source>InfoService</source>
</properties>
</destination>
Last, this service is invoked by a client by using the RemoteObject class within ActionScript. Below is a small chunk of code that demonstrates how to use this class:
remoteObject = new RemoteObject();
remoteObject.destination = "InfoService";
remoteObject.getComputerInfo.addEventListener("result", onResult);
remoteObject.addEventListener("fault", onFault);
Assuming that the remote object variable was declared at the top of your MXML application, this code illustrates creating and initializing a remote object for use. Note in particular that the destination property is set to "InfoService", which maps directly to the ID attribute of the destination we just configured within remoting-config.xml. Note that this is how Flex (and WebORB) determines where to send this request. The final two lines above demonstrate adding callback methods to the remote object; the first line tells Flex to pass the result of a call to the getComputerInfo method (this maps to the Rails service method on the server) to the onResult method (which is on the client). The last line tells the remoteObject instance to pass any faults to the onFault method (also implemented in ActionScript). The example below shows the two event listeners that were registered above:
public function onFault(event:FaultEvent):void
{
Alert.show(event.fault.faultString, 'Error');
}
public function onResult(event:ResultEvent):void
{
var computerInfo:Object = event.result;
serverInfoText.text = computerInfo.serverName;
requestIdText.text = computerInfo.requestId;
osText.text = computerInfo.os;
timeText.text = computerInfo.currentTime.toString();
invokeButton.enabled = true;
}
Now the remote object can invoke the method on the server written in Ruby by simply calling:
remoteObject.getComputerInfo("ABC123");
and the results will be available in the event.result object that is passed to the onResult method as demonstrated above. In this example each property that is stored on the server is available as a property of the event.result object that we store above in the computerInfo instance. The source code for this example is available as part of the WebORB distribution for those interested in looking at the complete picture; after installing WebORB the server code is available in /app/services/InfoService.rb and the client code is available in /public/examples/example.mxml.
Advanced Features of WebORB
Active Record Integration
The previous example is a simple tutorial on how integrating Flex and Rails works using WebORB and the RemoteObject class. However, when building Rails applications, most of the interesting data for your application will be available via the ActiveRecord API in the data model layer. This is actually where WebORB provides a great deal of value: it natively serializes Rails model objects to Flex clients including handling any associations that are requested as part of an active record query.
Consider the following Ruby class that can be dropped into a ProductService.rb file within /app/services:
class ProductService
def getProducts
Product.find(:all, :include => [ :images ])
end
end
This service will return all the products in the database and include associated image records; this type of service would be great for displaying a product list within a DataGrid that also could display product images upon selecting a row in the grid. On the client side the results of this method invocation could be made available in an ActionScript method such as:
public function onGetProducts(event:ResultEvent):void
{
var products:Array = event.result as Array;
dataGrid.dataProvider = products;
}
Also note that within each product, another array is available that is accessed through the images property (the Image model in rails would likely include a URL or path attribute that Flex could use to load pictures). As an example, the following ActionScript method could be attached to the "change" event of the DataGrid:
public function onProductSelected():void
{
var product:Object = dataGrid.selectedItem;
for( var i:Number = 0; i < product.images.length; i++ )
{
var imageObject:Object = product.images[i];
// do something useful with imageObject.path attribute
}
}
Last, remember that if you do not want to include associated data (has_many/belongs_to relationships within Rails models), then simply do not pass the :include option to your query.
Access to the HTTP Request and Session
As a final note, another useful feature of WebORB is the ability to access the HTTP request or session objects within remote Rails services. These objects are available to standard Rails controllers that operate at the HTTP level; however, when using WebORB, developers simply develop "services" that are server methods that generally act as a layer between clients and Active Record models without inherent knowledge of the HTTP transport protocol. There will be times, however, when a service will need access to either the HTTP request or session. This is made available through a RequestContext class that can be included in any remote service. This technique was actually used in our first example. Note the "require 'weborb/context'" line within InfoService.rb listed above; this line imports the RequestContext class so that developers can access the HTTP request and session via the respective RequestContext.get_request and RequestContext.get_session class-level methods. Any data that is stored in the session will be available to subsequent requests using the standards Rails session API after retrieving the session object similar to:
session = RequestContext.get_session
#do something interesting with the session object
Basic Authentication Support
WebORB provides support for basic authentication of client applications. This allows credentials to be set on the RemoteObject instance, and services to access the associated user name and password on the server. On the client side this is done with ActionScript using the setCredentials method on a RemoteObject instance.
remoteObject.setCredentials("UserNameHere", "PasswordHere");
This information is available using the same RequestContext API discussed above. Within your service you can get the credentials using the API demonstrated below:
require 'weborb/context'
class SecureService
def doSomethingSecretive
user = RequestContext.get_user_name
password = RequestContext.get_password
//Authenticate credentials here, if unauthorized raise error
end
end
The one problem with this approach is that now the service code is contaminated with authentication code. Ideally this would happen before ever reaching the method (like using a "before filter" in Rails controllers. WebORB will eventually provide an interface that will authenticate users in a similar way before ever reaching secure methods. In the meantime, it is important to make this feature available for developers who need this capability today (WebORB on Rails will continue to support this API even after a cleaner approach is provided).
Conclusion
This article provided an initial glimpse into how Flex clients can be integrated with Ruby on Rails using WebORB's Flex RPC implementation and the RemoteObject API. While some applications with very simple data requirements can happily integrate Flex and Rails using model.to_xml and standard HTTP requests, WebORB on Rails simplifies the development process as the amount of client/server interaction scales to a large number of request/response types.