integrating flex and rails with rubyamf
DESCRIPTION
RubyAMF is a Rails plug-in that allows easy, fast integration between Flex apps and Rails using Adobe’s open format for transferring typed data to/from Flash apps. We’ll walk through building a Flex application powered by a Rails back-end service. You’ll see how to work with translation to native objects in both directions, working with hierarchical data and more advanced configuration options.TRANSCRIPT
Flex and Rails with RubyAMF
Tony HillersonSoftware ArchitectEffectiveUIRailsConf
Code and Slides:http://github.com/thillerson/preso_code/
Sample du Jour: Stuff
Why Flex and Rails?
They Make The Great Tag Team!
[SKIP INTRO]
What are the Options?
XML
XML is the Default Option
# POST /contexts# POST /contexts.xmldef create @context = Context.new(params[:context]) respond_to do |format| if @context.save flash[:notice] = 'Context was successfully created.' format.html { redirect_to(@context) } format.xml { render :xml => @context, :status => :created, :location => @context } else format.html { render :action => "new" } format.xml { render :xml => @context.errors, :status => :unprocessable_entity } end endend
JSON
Javascript Object Notation
JSON is in Rails Tooformat.json { render :json => @context.to_json }
http://as3corlib.googlecode.com
var obj:Object = JSON.decode(jsonString)
AMF
Action Message Format
AMF is the Good Stuff
Buck Thinks it’s Great!
RubyAMF
http://rubyamf.orghttp://rubyamf.googlecode.com
Installing RubyAMF$ script/plugin install http://rubyamf.googlecode.com/svn/current/rubyamf
• New File: app/controllers/rubyamf_controller.rb• New File: config/rubyamf_config.rb• config/initializers/mime_types.rb modified: Mime::Type.register "application/x-amf", :amf• config/routes.rb modified: ActionController::Routing::Routes.draw do |map| map.rubyamf_gateway 'rubyamf_gateway', :controller => 'rubyamf', :action => 'gateway' end
Con"guring RubyAMFmodule RubyAMF module Configuration ClassMappings.translate_case = true ClassMappings.assume_types = false ParameterMappings.scaffolding = true ClassMappings.register( :actionscript => 'Task', :ruby => 'Task', :type => 'active_record', #:associations => ["context"], :attributes => ["id", "label", "context_id", "completed_at", "created_at", "updated_at"]) endend
Con"guring RubyAMFClassMappings.translate_case = false
public var created_at:Date;
ClassMappings.translate_case = true
public var createdAt:Date; // created_at in rails
Con"guring RubyAMFClassMappings.assume_types = true
class Context < ActiveRecord::Base
[RemoteClass(alias="Context")]public class Context {
matches
for free
Con"guring RubyAMFClassMappings.assume_types = false
class Context < ActiveRecord::Base
[RemoteClass(alias="Context")]public class Context {
matches
ClassMappings.register( :actionscript => 'Context', :ruby => 'Context', :type => 'active_record', :attributes => ["id", ...])
with registration
Con"guring RubyAMFParameterMappings.scaffolding = false
save(context);def save @context = params[0]becomes
ParameterMappings.scaffolding = true
save( {context:context});
def save @context = params[:context]becomes
Connecting to Rails via RubyAMF
<mx:RemoteObject id="contextsService" destination="rubyamf" endpoint="http://localhost:3000/rubyamf_gateway/" source="ContextsController" showBusyCursor="true"/>public function save(context:Context):void { var call:AsyncToken =
contextsService.save({context:context}); call.addResponder(responder);}
Development Work#ow
1. Generate and Migrate$ script/generate rubyamf_scaffold context label:string
$ rake db:migrate
class CreateContexts < ActiveRecord::Migration def self.up create_table :contexts do |t| t.string :label t.timestamps end end
def self.down drop_table :contexts endend
def load_all @contexts = Context.find :all respond_to do |format| format.amf { render :amf => @contexts } end end def save respond_to do |format| format.amf do if params[:context].save render :amf => params[:context] else render :amf =>
FaultObject.new(params[:context].errors.join("\n")) end end end end
2. Sample Datawork: id: 1 label: Work
home: id: 2 label: Home
anarco_syndicalist_commune_biweekly_meetings: id: 3 label: Anarcho-syndicalist Commune Bi-weekly Meetings
3. Test
class ContextTest < ActiveSupport::TestCase def test_context_without_label_fails non_label_context = Context.new assert !(non_label_context.save) error_messages = non_label_context.errors.on(:label) assert !(error_messages.empty?) end
class Context < ActiveRecord::Base validates_presence_of :label
4. Con"gure
ClassMappings.register( :actionscript => 'Context', :ruby => 'Context', :type => 'active_record', #:associations => ["tasks"], :attributes => ["id", "label", "created_at", "updated_at"])
5. Wire<mx:RemoteObject id="contextsService" destination="rubyamf" endpoint="http://localhost:3000/rubyamf_gateway/" source="ContextsController" showBusyCursor="true"/>
<mx:RemoteObjectid="tasksService"
destination="rubyamf" endpoint="http://localhost:3000/rubyamf_gateway/" source="TasksController" showBusyCursor="true"/>
5. Wirepublic function loadAll():void { var call:AsyncToken = service.load_all(); call.addResponder(responder);}
public function save(context:Context):void { var call:AsyncToken =
service.save({context:context}); call.addResponder(responder);}
public function destroy(context:Context):void { var call:AsyncToken =
service.destroy({id:context.id}); call.addResponder(responder);}
5. Wirepublic function execute(event:CairngormEvent):void { var evt:SaveContextEvent = event as SaveContextEvent; var delegate:ContextsDelegate = new ContextsDelegate(this); delegate.save(evt.context);}
public function result(data:Object):void { var result:ResultEvent = data as ResultEvent; var context:Context = result.result as Context; ...}
X. Rinse and Repeat
The Future
GemPlugin + GemC Extension
GemPlugin
C Extension
An Impassioned Plea
Resources:
http://rubyamf.googlecode.comhttp://groups.google.com/group/rubyamfhttp://github.com/thillerson/rubyamf
Thanks!Tony Hillersonhttp://slideshare.com/thillersonhttp://github.com/thillersonhttp://thillerson.blogspot.comhttp://effectiveui.com
Twitter: thillersonBrightkite: thillerson
39
You
YourFather
Bob