Vous êtes sur la page 1sur 39

Flex and Rails Tony Hillerson

Software Architect

with RubyAMF EffectiveUI


RailsConf
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.xml
def 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
end
end
JSON

Javascript Object Notation


JSON is in Rails Too
format.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.org
http://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
Configuring RubyAMF
module 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"])
end
end
Configuring RubyAMF
ClassMappings.translate_case = false

public var created_at:Date;

ClassMappings.translate_case = true

public var createdAt:Date; // created_at in rails


Configuring RubyAMF
ClassMappings.assume_types = true

class Context < ActiveRecord::Base


matches
[RemoteClass(alias="Context")]
public class Context {

for free
Configuring RubyAMF
ClassMappings.assume_types = false

class Context < ActiveRecord::Base


matches
[RemoteClass(alias="Context")]
public class Context {

with registration
ClassMappings.register(
:actionscript => 'Context',
:ruby => 'Context',
:type => 'active_record',
:attributes => ["id", ...])
Configuring RubyAMF
ParameterMappings.scaffolding = false

def save
save(context); becomes @context = params[0]

ParameterMappings.scaffolding = true
def save
save(
@context =
{context:context} becomes params[:context]
);
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 Workflow
1. Generate and Migrate
$ script/generate rubyamf_scaffold context label:string
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
end
end
$ rake db:migrate
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 Data
work:
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 Context < ActiveRecord::Base
validates_presence_of :label

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
4. Configure

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:RemoteObject
id="tasksService"
destination="rubyamf"
endpoint="http://localhost:3000/rubyamf_gateway/"
source="TasksController"
showBusyCursor="true"
/>
5. Wire
public 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. Wire
public 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
Gem
Plugin + Gem
C Extension
Gem
Plugin
C Extension
An Impassioned Plea
Resources:

http://rubyamf.googlecode.com
http://groups.google.com/group/rubyamf
http://github.com/thillerson/rubyamf
Your
Bob
Father

You

Thanks!
Tony Hillerson
http://slideshare.com/thillerson
http://github.com/thillerson
http://thillerson.blogspot.com
http://effectiveui.com

Twitter: thillerson
Brightkite: thillerson

39

Vous aimerez peut-être aussi