Category: Ruby/Rails


Wednesday 2008/04/09
2:19 PM

Categories:

Apple, Flash/Actionscript, OS X, Ruby/Rails, Web Dev

Plugout - Flash Player Version Switcher

While developing the recent AllStateGarage.com site I had to do regression testing on different versions of the Flash Player, to make sure that both the swfobject embedding script and the built-in ExpressInstall upgrade functionality were working properly. After doing a bit of searching I found Plugout, which in a brilliant twist of fate was written by Aaron Smith (the guy behind RubyAMF that we used on the AllstateGarage.com project).

Plugout is a command-line utility that makes switching to different versions of the flash player easy. You can specify the plugin, version number, and browser. It's smart enough to restart and run the browser under Rosetta if the plugin version is PPC-only. For example, to switch to Flash Player version 9.0.28 in Safari I fire up Terminal and run:

CODE:
  1. plugout -p flash -v 9.0.28

You can also add different plugin versions as they get released, including debugger versions of the plugin (the debugger versions are denoted by a "d" following the version number). For example:

CODE:
  1. plugout -p flash -v 9.0.115d

The only wrinkle I ran into when using Plugout was that Ruby is required for it to work. This isn't a big deal to Leopard users, since Ruby is included, but before I upgraded to OS X 10.5 I just ran the plugout command in a shell session launched from within a Locomotive Ruby context. Speaking of Locomotive: development has been halted on the project, mostly because of Ruby's inclusion in OS X Leopard.


Tuesday 2008/04/08
10:00 AM

Categories:

Flash/Actionscript, Ruby/Rails, RubyAMF, Web Dev, Work

AllstateGarage.com

FWA

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.


Thursday 2007/10/25
2:41 PM

Categories:

Flash/Actionscript, Ruby/Rails, RubyAMF, Web Dev, Work

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:

Actionscript:
  1. // remoting
  2. import mx.remoting.Service;
  3. import mx.remoting.PendingCall;
  4. import mx.rpc.RelayResponder;
  5. import mx.rpc.ResultEvent;
  6. import mx.rpc.FaultEvent;
  7.  
  8. var peopleService:Service = new Service("http://localhost:3000/rubyamf/gateway", null, "PeopleController", null, null);
  9. var peopleCall:PendingCall = peopleService.index();
  10. peopleCall.responder = new RelayResponder(this, "onList", "onFault");
  11.  
  12.  
  13. function onList(re: ResultEvent): Void
  14. {
  15.     var people:Object = re.result;
  16.     for (var i = 0; i <people.length; i++) {
  17.         for (var j in people[i])
  18.         {
  19.             trace(j + ": " + people[i][j]);
  20.         }
  21.     }   
  22. }
  23.  
  24. function onFault(fault:FaultEvent): Void
  25. {
  26.     trace("PeopleRest::onFault: " + fault);
  27. }


Monday 2007/10/22
10:25 AM

Categories:

Flash/Actionscript, Ruby/Rails, RubyAMF, Web Dev, Work

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:

RUBY:
  1. def index
  2.     @people = Person.find(:all)
  3.  
  4.     respond_to do |format|
  5.       format.html # index.rhtml
  6.       format.xml  { render :xml => @people.to_xml }
  7.       format.amf { render :amf => @people }
  8.     end
  9. 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:

Actionscript:
  1. package {
  2.     import flash.net.Responder;
  3.     import flash.display.MovieClip;
  4.     import fl.controls.DataGrid;
  5.     import fl.data.DataProvider;
  6.     import flash.events.Event;
  7.  
  8.     import org.rubyamf.remoting.ssr.*;
  9.  
  10.     public class PeopleRest extends MovieClip
  11.     {
  12.         private var rs:RemotingService;
  13.         private var peopleGrid:DataGrid;
  14.  
  15.         public function PeopleRest()
  16.         {
  17.             init();
  18.         }
  19.  
  20.         private function init(): void
  21.         {
  22.             peopleGrid = new DataGrid();
  23.             peopleGrid.x = 50;
  24.             peopleGrid.y = 180;
  25.             peopleGrid.width = 400;
  26.             addChild(peopleGrid);
  27.  
  28.             rs = new RemotingService("http://localhost:3000/rubyamf/gateway", "PeopleController");
  29.             rs.addEventListener(FaultEvent.CONNECTION_ERROR, onConnectFault);
  30.             rs.addHeader('recordset_format',false,'fl9');
  31.             rs.index([], onList, onFault);
  32.         }
  33.  
  34.         private function onList(re:ResultEvent=null):void {
  35.             var people:Object = re.result;
  36.             var dp:DataProvider = new DataProvider(re.result);
  37.             peopleGrid.dataProvider = dp;
  38.         }
  39.  
  40.         private function onFault(fault:FaultEvent):void
  41.         {
  42.             trace("PeopleRest::onFault: " + fault.fault.faultString);
  43.         }
  44.  
  45.         private function onConnectFault(fe:FaultEvent):void
  46.         {
  47.             trace("PeopleRest::onConnectFault() " + fe);
  48.         }
  49.  
  50.     };
  51.  
  52. }

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:

RUBY:
  1. def create
  2.   if @is_amf
  3.     @person = Person.new();
  4.     @person.first_name = params[:first_name]
  5.     @person.last_name = params[:last_name]
  6.   else
  7.     @person = Person.new(params[:person])
  8.   end
  9.  
  10.   respond_to do |format|
  11.     if @person.save
  12.       flash[:notice] = 'Person was successfully created.'
  13.       format.html { redirect_to person_url(@person) }
  14.       format.xml  { head :created, :location => person_url(@person) }
  15.       format.amf { render :amf => @person }
  16.     else
  17.       format.html { render :action => "new" }
  18.       format.xml  { render :xml => @person.errors.to_xml }
  19.     end
  20.   end
  21. end

Update:

RUBY:
  1. def update
  2.   @person = Person.find(params[:id])
  3.  
  4.   if @is_amf
  5.     @person=Person.find(params[:id])
  6.     @person.first_name=params[:first_name]
  7.     @person.last_name=params[:last_name]
  8.   else
  9.     @event = Person.new(params[:person])
  10.   end 
  11.  
  12.   respond_to do |format|
  13.     if @person.update_attributes(params[:person])
  14.       flash[:notice] = 'Person was successfully updated.'
  15.       format.html { redirect_to person_url(@person) }
  16.       format.xml  { head :ok }
  17.       format.amf { render :amf => @person }
  18.     else
  19.       format.html { render :action => "edit" }
  20.       format.xml  { render :xml => @person.errors.to_xml }
  21.     end
  22.   end
  23. end

Destroy:

RUBY:
  1. def destroy
  2.   @person = Person.find(params[:id])
  3.   @person.destroy
  4.  
  5.   respond_to do |format|
  6.     format.html { redirect_to people_url }
  7.     format.xml  { head :ok }
  8.     format.amf { render :amf => 'deleted' }
  9.   end
  10. end

The final FLA, Actionscript3 document class, and rails controller file are here: people_rest.zip.


Tuesday 2007/08/28
10:43 AM

Categories:

Flash/Actionscript, Ruby/Rails, TextMate, Web Dev

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:

Actionscript:
  1. package
  2. {
  3.     import flash.net.Responder;
  4.     import flash.display.Sprite;
  5.     import org.rubyamf.remoting.ssr.*;
  6.    
  7.     public class RemotingTest extends Sprite
  8.     {
  9.         private var rs:RemotingService;
  10.        
  11.         function RemotingTest()
  12.         {
  13.             init();
  14.         }
  15.        
  16.         private function init():void
  17.         {   
  18.             trace("RemotingTest::init() ");
  19.             rs = new RemotingService("http://localhost:3000/rubyamf/gateway", "TestWorldController");
  20.             rs.hello_world([], onResult, onFault);
  21.         }
  22.                                                
  23.         private function onResult(re:ResultEvent):void
  24.         {
  25.             trace("RemotingTest::onResult() " + re.result.toString());
  26.         }
  27.        
  28.         private function onFault(fault:FaultEvent):void
  29.         {
  30.             trace("onFault: " + fault);
  31.         }
  32.  
  33.     }
  34. }

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.