Category: Web Dev
AllstateGarage.com

AllStateGarage.com is today’s Site of the Day from The FWA. This is a project I’ve been working on for the last 7-8 months (on and off), so it’s nice to see it pick up some accolades. The project was a lot of fun from the programming standpoint — we got to use RubyAMF to hook into the Rails backend, so there was a lot of digging into new technology.
The Squid and the Stallion has more on the project.
RubyAMF and AS2 (follow-up to AS3 + SSR, RubyAMF, and RESTful Rails)
A quick follow-up post to my tutorial on Flash and RubyAMF — RubyAMF can of course be used with AS2. Here's a short AS block showing a call to the index method of the PeopleController:
-
// remoting
-
import mx.remoting.Service;
-
import mx.remoting.PendingCall;
-
import mx.rpc.RelayResponder;
-
import mx.rpc.ResultEvent;
-
import mx.rpc.FaultEvent;
-
-
var peopleService:Service = new Service("http://localhost:3000/rubyamf/gateway", null, "PeopleController", null, null);
-
var peopleCall:PendingCall = peopleService.index();
-
peopleCall.responder = new RelayResponder(this, "onList", "onFault");
-
-
-
function onList(re: ResultEvent): Void
-
{
-
var people:Object = re.result;
-
for (var i = 0; i <people.length; i++) {
-
for (var j in people[i])
-
{
-
trace(j + ": " + people[i][j]);
-
}
-
}
-
}
-
-
function onFault(fault:FaultEvent): Void
-
{
-
trace("PeopleRest::onFault: " + fault);
-
}
AS3 + SSR, RubyAMF, and RESTful Rails
Update 2008-05-02: This example was written using SSR v1 and RubyAMF 1.3.4, and does not currrently match what you get with the latest versions. I'll be updating it shortly to reflect the changes against both SSR and RubyAMF.
Update 2007-10-25: A quick AS2 example using the Rails controller detailed below can be found here.
The RubyAMF blog recently linked to a good tutorial on using Flex, RubyAMF, and RESTful Rails. At Domani we've been using RubyAMF for a few projects recently, but without Flex. So here's a quick tutorial on using Flash, SSR (Super Simple Remoting), and RubyAMF with RESTful Rails in a local development environment. This assumes the usage of OS X, Locomotive, and MAMP — for some notes on setting that up I wrote a quick post on setting that up here. As always, many thanks to Aaron and the crew behind RubyAMF for their work and quick responses to questions.
Set Up Your Database
Create a new database called people_development. I used the phpMyAdmin interface running on the MAMP instance to do this.
Next, create a new rails app in Locomotive (Applications > Create New). I called the app people. The first thing I usually do is bring up the info screen for the newly-created app and change the port from the default set by Locomotive. I've noticed that the listing in the main Locomotive window will still display the default port even after you change it; to avoid this hit tab from the port field while you're in the info screen and it should refresh the display in the main window.
Modify the database config file (config > database.yml) to add two things:
port: 8889
socket: /Applications/MAMP/tmp/mysql/mysql.sock
Also set the password to "root", which is the default for databases served by MAMP.
Select the Rails app in the main Locomotive listing, and hit Command+T to fire up a terminal session in the context of the app you created. From the terminal session run this command (one line):
ruby script/generate scaffold_resource person first_name:string last_name:string
Among other things, this will create a migration that we can run to create a table for our app in the database. From the terminal run:
rake db:migrate
At this point you should have people table in the people_development database.
Install RubyAMF
From your terminal session run (one line):
ruby script/plugin install http://rubyamf.googlecode.com/svn/trunk/rubyamf
After RubyAMF finishes the install, start the people app in Locomotive. Verify that the RubyAMF gateway is live by pointing your browser to http://localhost:3000/rubyamf/gateway.
Next, verify that the app is live by pointing your browser to http://localhost:3000/people. Create a few people to populate the database with some entries.
Add AMF format response
Add a line for the amf format response in the people controller file (app > controllers> people_controller.rb)
format.amf { render :amf => @people }
The index method should read:
-
def index
-
@people = Person.find(:all)
-
-
respond_to do |format|
-
format.html # index.rhtml
-
format.xml { render :xml => @people.to_xml }
-
format.amf { render :amf => @people }
-
end
-
end
Set Up Your Flash App
Create a new FLA called people_rest.fla. Drag a DataGrid component onto the stage so that the library contains the DataGrid symbol and the DataGrid classes can be. You can delete the DataGrid off the stage after this.
Download SSR from here. Unzip the folder, and move the org folder to the same location as your FLA.
Create a document class called PeopleRest.as, and link it to your FLA as the Document class via the Properties panel. PeopleRest.as will establish a connection to the Rails app via the RubyAMF gateway and make a call to the index method.
PeopleRest.as:
-
package {
-
import flash.net.Responder;
-
import flash.display.MovieClip;
-
import fl.controls.DataGrid;
-
import fl.data.DataProvider;
-
import flash.events.Event;
-
-
import org.rubyamf.remoting.ssr.*;
-
-
public class PeopleRest extends MovieClip
-
{
-
private var rs:RemotingService;
-
private var peopleGrid:DataGrid;
-
-
public function PeopleRest()
-
{
-
init();
-
}
-
-
private function init(): void
-
{
-
peopleGrid = new DataGrid();
-
peopleGrid.x = 50;
-
peopleGrid.y = 180;
-
peopleGrid.width = 400;
-
addChild(peopleGrid);
-
-
rs = new RemotingService("http://localhost:3000/rubyamf/gateway", "PeopleController");
-
rs.addEventListener(FaultEvent.CONNECTION_ERROR, onConnectFault);
-
rs.addHeader('recordset_format',false,'fl9');
-
rs.index([], onList, onFault);
-
}
-
-
private function onList(re:ResultEvent=null):void {
-
var people:Object = re.result;
-
var dp:DataProvider = new DataProvider(re.result);
-
peopleGrid.dataProvider = dp;
-
}
-
-
private function onFault(fault:FaultEvent):void
-
{
-
trace("PeopleRest::onFault: " + fault.fault.faultString);
-
}
-
-
private function onConnectFault(fe:FaultEvent):void
-
{
-
trace("PeopleRest::onConnectFault() " + fe);
-
}
-
-
};
-
-
}
Compile the movie. You should see the person entries in your database in the data grid component on stage.
Adding Create/Update/Destroy Functionality
At this point you can add functionality to PeopleRest.as by adding input fields and buttons for triggering calls to the create, update, and destroy methods in the controller. Below are the edits to the Rails controller that are needed to support AMF responses:
Create:
-
def create
-
if @is_amf
-
@person = Person.new();
-
@person.first_name = params[:first_name]
-
@person.last_name = params[:last_name]
-
else
-
@person = Person.new(params[:person])
-
end
-
-
respond_to do |format|
-
if @person.save
-
flash[:notice] = 'Person was successfully created.'
-
format.html { redirect_to person_url(@person) }
-
format.xml { head :created, :location => person_url(@person) }
-
format.amf { render :amf => @person }
-
else
-
format.html { render :action => "new" }
-
format.xml { render :xml => @person.errors.to_xml }
-
end
-
end
-
end
Update:
-
def update
-
@person = Person.find(params[:id])
-
-
if @is_amf
-
@person=Person.find(params[:id])
-
@person.first_name=params[:first_name]
-
@person.last_name=params[:last_name]
-
else
-
@event = Person.new(params[:person])
-
end
-
-
respond_to do |format|
-
if @person.update_attributes(params[:person])
-
flash[:notice] = 'Person was successfully updated.'
-
format.html { redirect_to person_url(@person) }
-
format.xml { head :ok }
-
format.amf { render :amf => @person }
-
else
-
format.html { render :action => "edit" }
-
format.xml { render :xml => @person.errors.to_xml }
-
end
-
end
-
end
Destroy:
-
def destroy
-
@person = Person.find(params[:id])
-
@person.destroy
-
-
respond_to do |format|
-
format.html { redirect_to people_url }
-
format.xml { head :ok }
-
format.amf { render :amf => 'deleted' }
-
end
-
end
The final FLA, Actionscript3 document class, and rails controller file are here: people_rest.zip.
A Quick RubyAMF Test
Update 2007-10-22: Updated the line with the RubyAMF installer to point to the new googlecode location. Updated the link to the SSR library.
Update 2007-08-30: Seth's comment below revealed the need for a cross-domain policy file in /public when testing this via the browser. I did all my testing from the flash debug player and the IDE, so I didn't run into this while writing this up. Aaron has said that he'll include the crossdomain policy file as part of the RubyAMF installer in the future.
Back from my Seattle/Portland vacation with Jordan (details on that to follow, but photos are up on Flickr).
Another quick Rails experiment, this time checking out RubyAMF. I wanted to run the RubyAMF gateway as a Rails plugin, so I used this Flex/Rails screencast on the RubyAMF blog as a reference for getting the Rails part done. You might want to view my earlier post on setting up Locomotive with MAMP.
I first created a new Rails app in Locomotive called test_hello_world (I also switched the port from 3001 to 3000). Once that was done I simply replicated the steps in the screencast:
Download RubyAMF.Create a rubyamf folder in the test_hello_world/vendor/plugins directory.Copy the contents of the RubyAMF download to the rubyamf directory.Copy the rubyamf/services/rubyamf_controller.rb file to the test_hello_world/app/controllers directory.- As per Aaron's note below, use the rails installer. Type ruby script/plugin install http://rubyamf.googlecode.com/svn/trunk/rubyamf
- Start the Rails app from Locomotive.
- Test the RubyAMF gateway at http://localhost:3000/rubyamf/gateway.
- Generate TestWorld controller. This can be done by opening a Terminal/iTerm session in the current Rails app context via the Locomotive > Applications > Open Terminal (Command-T) item. Once that's done you can type: ruby/script/generate controller TestWorld
- Define a hello_world method in the controller to return the text string "Hello World!"
At this point the screencast goes into Flex, but I decided to make use of the Super-Simple Remoting (SSR) library from RubyAMF. I copied the source files to a folder containing my test AS3 script RemotingTest.as. Here's the contents of RemotingTest.as:
-
package
-
{
-
import flash.net.Responder;
-
import flash.display.Sprite;
-
import org.rubyamf.remoting.ssr.*;
-
-
public class RemotingTest extends Sprite
-
{
-
private var rs:RemotingService;
-
-
function RemotingTest()
-
{
-
init();
-
}
-
-
private function init():void
-
{
-
trace("RemotingTest::init() ");
-
rs = new RemotingService("http://localhost:3000/rubyamf/gateway", "TestWorldController");
-
rs.hello_world([], onResult, onFault);
-
}
-
-
private function onResult(re:ResultEvent):void
-
{
-
trace("RemotingTest::onResult() " + re.result.toString());
-
}
-
-
private function onFault(fault:FaultEvent):void
-
{
-
trace("onFault: " + fault);
-
}
-
-
}
-
}
Note that when we create an instance of the Remoting service we pass it the path to the gateway, and the name of the controller which we just created (TestWorldController). Once that is defined we can then just call methods in that controller like so:
rs.hello_world([], onResult, onFault);
The empty array parameter is there because the method accepts no parameters.
I merely had the result piped to trace output, but you can have it piped to an onscreen text field as well if you don't have logging set up.
I was using the still-in-development AS3/Flex bundle (more on installing/modifying that in a following post) to compile RemotingTest.as into a SWF, but you should be able to link it as a document class to an FLA and generate the SWF that way.
Locomotive on Rails, with MAMP as a Caboose
Update 2008-07-14: Looks like Locomotive is no longer being distributed, since OS X 10.5 now ships with Ruby on Rails installed.
Pretty soon we'll have a framework called "ChooChoo" just to take this metaphor to its logical demise. I've just started dipping my toe into Ruby on Rails, and have found it relatively easy to get up and running on OS X. I've been using a combination of MAMP and Locomotive. MAMP, of course, is the Macintosh/Apache/MySQL/PHP app that takes the pain out of setting up those respective components and allows you to focus on writing code. Locomotive is similar in that it takes care of setting up your Rails environment so you can start developing. In this situation MAMP is only being used for the MySQL component. I have a feeling Locomotive will eventually have this as part of its package, making things even easier.
There were two things I needed to do to get my setup working smoothly:
- Tell Locomotive to use MAMP for MySQL. I did this by going to Locomotive > Preferences > Terminal and putting "/Applications/MAMP/db/mysql/" in the Additional Paths field.
- From this tip at aralbakan.com: adding a socket definition to my database config file - “socket: /Applications/MAMP/tmp/mysql/mysql.sock”
I like that you can open up a terminal session from Locomotive and it'll set the context to be the Locomotive Rails environment - this way I don't have to mess with setting up my PATH to point to the Locomotive's Ruby instead of the default OS X one.
TextMate, of course, makes working with Ruby/Rails quite easy. I've been spending some time in Flex Builder lately, and coming back to the TextMate environment is a breath of cleaner, simpler air.
This was the tutorial I started out with: Using Ruby on Rails for Web Development on Mac OS X.
I also ran through the Merb/AIR tutorial here: Merb on AIR - Drag and Drop Multiple File Upload. Merb isn't Rails per se, but the example illustrates the way that Ruby apps can be used with AIR/Flash applications.







