RubyOnRails (1.1) and Flex (2.0): Pt 1

April 16th, 2006

UPDATE: Part 2 of the tutorial can be found here

Some close friends of mine are dangerously good flash developers. In a recent pub meet-up I said I had some ideas on integrations between Ruby On Rails and Adobe’s new Flex framework.

Now I know that Ruby On Rails is all integrated with some cool AJAX features (I’m loving those RJS templates right now) but Flex does offer something different.

For the un-informed, Flex allows you to build Rich Internet Applications, defined in XML and delivered on the Flash player. Let’s set one thing straight Flex is Free The SDK and compiler cost nothing. Adobe are making the dough on the IDE Flex Builder and some of the harder core Java integration features.

So where does Rails come in to this. Well Flex can consume and publish to XML based URL services to create dynamic applications with a rich client. Rails1.1 has some great REST features which make it a truely rapid development backend for Flex applications.

So without much more ado here is the first part of a tutorial on integrating RubyOnRails and Flex. This is the simplest thing that works tutorial. The Part 2 tutorial is going to cover some more advanced integrations.

Environment

The first thing lets make sure we have a working Ruby on Rails environment. You’ll also need a database of course.

You are going need at least 1.1 version of Rails for this tutorial. If you don’t have Rails running consider InstantRails for Windows or if you are on a Mac try Locomotive. But for the purpose of this tutorial you might want Windows as Flex Builder is only installable on Windows for now. You can use the Flex compiler on a Mac but the Builder IDE is just so much easier. I’m ok, i have a dual booting MBP ;-)

Then you are going to need to install the beta of Flex2.0 from Adobe. You can get this over at Adobe Labs. If you are on Windows just install the Flex Builder which will have everything you need, including the Flex Player 8.5 beta. If not you are going to need to install Flex PLyaer 8.5 beta and the Flex SDK.

Setup our Rails application

Ok so here we go.

First lets create a Rails application..you know how this goes. On the command line with me..


rails flexiblerails

You’ll also need a database for this application called flexiblerails_development.

We need to create a database table in our application called reviews

So try this for a mysql database

DROP DATABASE IF EXISTS `flexiblerails_development`; CREATE DATABASE `flexiblerails_development` USE `flexiblerails_development`; CREATE TABLE `reviews` ( `id` int(11) NOT NULL auto_increment, `title` varchar(255) default NULL, `text` text, `score` int(11) default NULL, `author` varchar(120) default NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1;

Lets create the model and controller

ruby script/generate model Review
ruby script/generate controller Reviews

Now we have our basic application we are going to add to.

Setup our Flex application

If you are using Flex Builder this is a piece of cake. Startup the builder and use the menu File > New > Flex Application. You don’t need any dataservices, call it flexiblerails and click Finish.

You should see the a new MXML file like this


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" layout="absolute">

</mx:Application>

Thats it.

Displaying some data

Simple scaffolding thing first. We want our Flex application to show our list of Reviews in a nice grid.

First lets create the Rails back-end. Open app/controllers/reviews_controller. Change it to:


class ReviewsController < ApplicationController
    def list
      @reviews = Review.find :all
      render :xml => @reviews.to_xml
    end
end

Rails 1.1 makes this very easy, all models can just be dumped straight to XML.

And start the server

ruby script/server

We shall add some content in the database.


INSERT INTO `reviews` (`id`,`title`,`text`,`score`,`author`) 
VALUES (1,'Agile Web Development with Rails',
 'This is the text for Rails programming and a fine read all round',5,'David Heinemeier Hansson');
INSERT INTO `reviews` (`id`,`title`,`text`,`score`,`author`) 
VALUES (2,'Programming Rails',
'Rubby Russell\'s new Rails book for O\'Reilly. Highly anticipated.',4,'Robby Russell');

And check our Rails controller. Lets go to http://localhost:3000/reviews/list and see the action result XML.


<reviews>
  <review>
    <score type="integer">5</score>
    <title>Agile Web Development with Rails</title>
    <text>
      This is the text for Rails programming and a fine read all round
    </text>
    <author>David Heinemeier Hansson</author>
    <id type="integer">1</id>
  </review>
  <review>
    <score type="integer">4</score>
    <title>Programming Rails</title>
    <text>
      Rubby Russell's new Rails book for O'Reilly. Highly anticipated.
    </text>
    <author>Robby Russell</author>
    <id type="integer">2</id>
  </review>
</reviews>

Lets get Flex to consume this new XML service. In the Flex Builder change the flexiblerails.mxml file to:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
                xmlns="*" layout="absolute" 
                creationComplete="reviewRequest.send()">
    <mx:HTTPService id="reviewRequest" 
                    url="http://localhost:3000/reviews/list" 
                    useProxy="false"/>
    <mx:DataGrid id="dgReviews" x="40" y="85" width="800" 
                 height="134" 
                 dataProvider="{reviewRequest.lastResult.reviews.review}">
        <mx:columns>
            <mx:DataGridColumn headerText="Title" dataField="title" width="480"/>
            <mx:DataGridColumn headerText="Author" dataField="author" width="240"/>
            <mx:DataGridColumn headerText="Score" dataField="score" width="80"/>
        </mx:columns>
    </mx:DataGrid>

    <mx:TextArea x="40" y="245" width="800" 
                 htmlText="{dgReviews.selectedItem.text}" />
</mx:Application>

The above MXML code creates fourthings.


<mx:HTTPService id="reviewRequest" url="http://localhost:3000/reviews/list" useProxy="false"/>

Creates a HTTPService which will access the list action on our ReviewsController.


<mx:DataGrid id="dgReviews" x="40" y="85" width="800" height="134" 
             dataProvider="{reviewRequest.lastResult.reviews.review}">
        <mx:columns>
            <mx:DataGridColumn headerText="Title" dataField="title" width="480"/>
            <mx:DataGridColumn headerText="Author" dataField="author" width="240"/>
            <mx:DataGridColumn headerText="Score" dataField="score" width="80"/>
        </mx:columns>
    </mx:DataGrid>

This MXML creates a DataGrid, a table to display our data. The dataProvider element points to the result of our HTTPService with reviewRequest.result. The last reviews.review is a dot-notation that references the reviews node, then all the review nodes will form the rows.

In the DataGrid all the DataGridColumn elements create a column where the dataField attribute references the XML node child of the review node.


<mx:TextArea x="40" y="245" width="800" htmlText="{dgReviews.selectedItem.text}" />

This textarea will display the review text of the selected item in the DataGrid.

We just need to make sure the request is kicked off, so in the mx:Application element we add:

creationComplete="reviewRequest.send()" 

Lets run our Flex application. If you are in builder just hit the green and white button.

You should get something like this:

Capturing data

All well and good but how do we capture data from Flex. Again Rails 1.1 makes this very easy.

Let’s start with the Flex side. Add the following the MXML file


    <mx:HTTPService contentType="application/xml" id="reviewCreateRequest" 
                    url="http://localhost:3000/reviews/create" 
                    useProxy="false" method="POST">
        <mx:request xmlns="">
            <review>
                <title>{fTitle.text}</title>
                <author>{fAuthor.text}</author>
                <score>{fScore.text}</score>
                <text>{fText.text}</text>
            </review>
        </mx:request>
    </mx:HTTPService>
    <mx:Form x="40" y="300" width="800">
    <mx:Grid>
        <mx:GridRow>
            <mx:GridItem>
                <mx:Label text="Title"/>
            </mx:GridItem>
            <mx:GridItem>
                <mx:TextInput width="260" id="fTitle"/>
            </mx:GridItem>
        </mx:GridRow>
        <mx:GridRow>
            <mx:GridItem>
                <mx:Label text="Author"/>
            </mx:GridItem>
            <mx:GridItem>
                <mx:TextInput width="140" id="fAuthor"/>
            </mx:GridItem>
        </mx:GridRow>
        <mx:GridRow>
            <mx:GridItem>
                <mx:Label text="Score"/>
            </mx:GridItem>
            <mx:GridItem>
                <mx:TextInput width="20" id="fScore"/>
            </mx:GridItem>
        </mx:GridRow>
        <mx:GridRow>
            <mx:GridItem>
                <mx:Label text="Text"/>
            </mx:GridItem>
            <mx:GridItem>
                <mx:TextArea width="600" height="200" id="fText"/>
            </mx:GridItem>
        </mx:GridRow>
        <mx:GridRow>
            <mx:GridItem>
                <mx:Button label="Submit" 
                   click="reviewCreateRequest.send();reviewRequest.send()"/>
            </mx:GridItem>
            <mx:GridItem>
            </mx:GridItem>
        </mx:GridRow> 
    </mx:Grid>
    </mx:Form>

This adds 2 things to our Flex application. A form and a new HTTPService. The form just lays out a series of fields and a button which calls a send on our new HTTPService.


 <mx:HTTPService contentType="application/xml" 
                 id="reviewCreateRequest" 
                 url="http://localhost:3000/review/create" 
                 useProxy="false" method="POST">
        <mx:request xmlns="">
            <review>
                <title>{fTitle.text}</title>
                <author>{fAuthor.text}</author>
                <score>{fScore.text}</score>
                <text>{fText.text}</text>
            </review>
        </mx:request>
    </mx:HTTPService>

This service is going to use a POST to send XML to a new Rails action create. The XML is formed in the request but subsituted with the values of the form fields. Note the contentType=”application/xml” it is important that Flex sends the XML content type to Rails.

For the Rails application we add a new action to ReviewsController


    def create
      @review = Review.new(params[:review])
      @review.save
      render :xml => @review.to_xml
    end

And thats it! Rails 1.1 will take a submitted request with an application/xml content-type and transform it to a parameter map which can be easily loaded into the models. It is then saved to the database and we return nothing. Equally here you could return error messages to be used in the Flex application.

So we start our new Flex application we get this:

If you enter data on the form and submit it will be added to the database and the list refreshed. A simple Flexible scaffold.

Summary

Ruby On Rails is a great back-end for Flex applications, with new 1.1 REST XML features it’s easy to do XML driven requests for Flash. With Flex it’s easy to consume them.

UPDATE: Part 2 of the tutorial is available

46 Responses to “RubyOnRails (1.1) and Flex (2.0): Pt 1”

  1. Richard Marsh Says:

    nice stuff matey, see you thursday at the MMUG :)

  2. Alex Says:

    Great Tutorial, Looking forward to Part 2

  3. cisnky Says:

    I’ve been thinking about doing something like this ever since I ran a scaffold command for the first time.

    Top article

  4. Campbell Says:

    Yeah! nice. Cisnky I totally agree. I think this is leading somewhere…..

  5. Richard Says:

    Just wondering when part 2 is coming out (it’s been two weeks now). Thanks

  6. .Netter Says:

    Is there a .Net version of this ^^?

  7. Stuart Eccles Says:

    Part 2 coming in the next couple of days, just have to write it up ;-)

  8. PsiliPharm Says:

    I thought I’d be the first to do this, I have a big project under development with Flex & Rails, but I’m waiting until final release of Flex 2 to launch the site, every Beta release I’ve had to change a bunch of code to get it working again…so I don’t want to launch until it’s a bit more stable.

  9. Andrew Cleland Says:

    Great article. I have been using Flex with a Java backend, but it seems like a pain in the a* to get my data from the db. I have heard of Rails, but never looked into it until yesterday. Your example makes it seem so easy, I am sure as with most examples that the logic and code can get quite complex. But you have shown me that I should really investigate Rails. There is a lot of technology out in the world, which gives solutions to either the client, i.e. Flex, or to the server, i.e. Rails. You brought the 2 together, which is what you want to do normally when developing applications.

  10. Toby Beal Says:

    I had difficulty in getting this example to work until I made a change to the dataProvider attribute of the DataGrid. I read somewhere that they made a change from Beta 2 to Beta 3, where you can no longer use “result” but you must intead use “lastResult” for the attribute.

    BEFORE reviewRequest.result.reviews.review

    AFTER reviewRequest.lastResult.reviews.review

  11. Toby Beal Says:

    Sorry. One more observation. I get an error from the flash client when using the code above. It seems that it doesn’t like the fact that it’s not getting XML return and it’s generating the following error:

    “Default decoder could not decode result”

    To fix this error I change the Rails code so that it renders the same list again.

    Example:

    BEFORE @review = Review.new(params[:review]) @review.save render :nothing => true

    AFTER @review = Review.new(params[:review]) @review.save render :xml => reviews.to_xml

    I should point out that I didn’t follow this tutorial exactly, and it may have been something I did. But to anyone out there getting this error. This was how I got around it.

  12. Stuart Eccles Says:

    Yep its a beta 2 to beta 3 issue with both of them. The first part was written with beta 2 and the second part was beta 2 hence why in part 2 all the actions render an XML result.

    I’ll update the article. Thanks for the help

  13. Austin Says:

    Amazing Job, I Have been looking for a interaction layer of MySql and Flex forever.

    Congrats on an excelent Toturial

  14. Thorsten Brueckner Says:

    Hello,

    first of all: Congratulations for doing a great job.

    Although I was able to see the Data grid (first half of tutorial), the Data did not come in.

    On the other hand I was able to see the xml generated from the table in the browser on http://localhost/reviews/list

    In the status line firefox told me “Waiting for localhost” when showing the swf-file

    Changing the port from 3000 to 80, using mongrel as Rails-Server, switching off windows firewall and several other tryings did not succeed.

    Any suggestions what am I doing wrong?

    Thank you

    Thorsten

  15. cskidmore Says:

    can someone look into what’s going on with this website? I’m trying to look at the tutorials on Rails & Flex but most of the links return an Application error or an Internal Server error.

  16. Gaurav Says:

    Great Job. I was looking for such a tutorial integrating rails & flex & I think I have found just that.

  17. Gaurav Says:

    I am unable to view the data in the table. Can anybody help me in this.

  18. Bounce Says:

    Hi Thorsten,

    I have the same problem. I am able to see the data at http://localhost:3000/reviews/list but not in the flex file. I get the following message from flex:

    [RPC Fault faultString=”Security error accessing url” faultCode=”Channel.Security.Error” faultDetail=”Destination: DefaultHTTP”] at mx.rpc::AbstractInvoker/http://www.adobe.com/2006/flex/mx/internal::faultHandler() at mx.rpc::Responder/fault() at mx.rpc::AsyncRequest/fault() at ::DirectHTTPMessageResponder/securityErrorHandler() at flash.events::EventDispatcher/flash.events:EventDispatcher::dispatchEventFunction() at flash.events::EventDispatcher/dispatchEvent() at flash.net::URLLoader/flash.net:URLLoader::redirectEvent()

    Can anyone help? Thanks. B.

  19. AJIT DIXIT Says:

    Hi ,

    In this example only in rails model Review you put following validation

    validates_presence_of :title

    How do you capture this in flex ?

  20. Magnus Says:

    It seems that I am having the same problems as Bounce and Thorsten: I can see the datagrid but no data. Firefox tells me: “Waiting for localhost”

    On IE I get the error:

    [RPC Fault faultString=”Security error accessing url” faultCode=”Channel.Security.Error” faultDetail=”Destination: DefaultHTTP”] at mx.rpc::AbstractInvoker/http://www.adobe.com/2006/flex/mx/internal::faultHandler() at mx.rpc::Responder/fault() at mx.rpc::AsyncRequest/fault() at ::DirectHTTPMessageResponder/securityErrorHandler() at flash.events::EventDispatcher/flash.events:EventDispatcher::dispatchEventFunction() at flash.events::EventDispatcher/dispatchEvent() at flash.net::URLLoader/flash.net:URLLoader::redirectEvent()

    Any suggestions?

  21. Anonymous Says:

    Hi Magnus,

    I haved the same problem

    Put your flexiblerails.swf in your flexiblerails\public directory.

    run ruby script\server -p 80

    Go to http://localhost/flexiblerails.swf with IE or Mozilla (with Flash Player 9)

    Voilà

  22. Anonymous Says:

    Sorry

    Change

    http://localhost:3000/reviews/list

    to

    http://localhost/reviews/list

    in your flexiblerails.mxml

    if you use -p 80 with ruby script\server

  23. Magnus Says:

    Oh Yes! Now it works :-) Thanks a lot.

  24. Laurent Says:

    Great article.

    But i have a problem to display the flash UI…i deployed the SWF in app/views/reviews folder then i try the url : http://localhost:3000/reviews/flexiblerails.swf but i get an error (Controller)

    Second solution, write a .rhtml view (index.rhtml for example) including the OBJECT tag: but nothing is displayed

    Any idea?

  25. Laurent Says:

    I’ve got a HTTP error 500..trying with Firefox, Flash 9, on Mac OS X Tiger

  26. Laurent Says:

    OK, now it works .. i started the server listening on port 80 and put the SWF in public folder.

    But my dataGrid is emty..when i check in a browser window the reviews/list page i got the xml.

  27. ? Says:

    part 2 is out since may:

    http://www.liverail.net/articles/2006/05/06/rubyonrails-1-1-and-flex-2-0-pt-2

  28. Dana Says:

    Thanks for the tutorial! One thing isn’t working for me now that I’ve finished it: when I click “Submit” the new record I entered doesn’t show up in the grid. I know it’s entered into database okay and the grid is indeed updated, because if I submit a second new record the first one I submitted will show up. If I submit a third the second will show up and so on. It’s as if rails is reporting back to the flex app before it’s done storing the new record. Is there some simple way to keep what’s in the database and what’s on the screen consistent?

  29. Dana Says:

    I think I may have found an answer to my question. Instead of having the submit button have click=”reviewCreateRequest.send();reviewRequest.send()” I cut the reviewRequest.send from there and added it to the reviewCreateRequest so it is now <mx:HTTPService contentType=”application/xml” id=”reviewCreateRequest” url=”http://localhost:3000/reviews/create” useProxy=”false” method=”POST” result=”reviewRequest.send()”>. The result=”reviewRequest.send()” is what I added. I have no idea if this is the way to do it, but it seems to work.

  30. Mircea Says:

    How can I send an xml like this:

    <events><updatetheme /></events> to a server.I used this code in flex: <?xml version=”1.0” encoding=”iso-8859-1”?> <mx:application> <mx:script> <![CDATA[ import mx.controls.Alert; public function submitForm():void { formSender.cancel(); formSender.send(registrationModel); } </mx:script> <mx:HTTPService id=”formSender” contentType=”application/xml” url=”http://localhost:8080/test/CNHost” method=”POST” showBusyCursor=”true” useProxy=”false” result=”getResultOk(1,event)” fault=”getResultOk(0,event)” resultFormat=”e4x” > </mx:httpservice> <mx:model> <root> <events><updatetheme></updatetheme></events> </root> </mx:model> <mx:form height="100%" width="100%"> <mx:button /> </mx:form> </mx:application>

    but the server receive the xml in the next form:

    <events><updatetheme><theme>blue</theme></updatetheme></events>

    but I need the server to receive this structure:

    <events><updatetheme /></events> In conclusion I don’t know how can I send xml attributes. Please HELP!!!!
  31. Mircea Says:

    How can I send an xml like this:

    <events><updatetheme /></events> to a server.I used this code in flex: <?xml version=”1.0” encoding=”iso-8859-1”?> <mx:application> <mx:script> <![CDATA[ import mx.controls.Alert; public function submitForm():void { formSender.cancel(); formSender.send(registrationModel); } </mx:script> <mx:HTTPService id=”formSender” contentType=”application/xml” url=”http://localhost:8080/test/CNHost” method=”POST” showBusyCursor=”true” useProxy=”false” result=”getResultOk(1,event)” fault=”getResultOk(0,event)” resultFormat=”e4x” > </mx:httpservice> <mx:model> <root> <events><updatetheme></events> </root> </mx:model> <mx:form height="100%" width="100%"> <mx:button /> </mx:form> </mx:application>

    but the server receive the xml in the next form:

    <events><updatetheme><theme>blue</theme></updatetheme></events>

    but I need the server to receive this structure:

    <events><updatetheme /></events> In conclusion I don’t know how can I send xml attributes. Please HELP!!!!
  32. Johannes Says:

    NetBeans IDE supports Ruby on Rails now. http://bits.netbeans.org/download/6_0/beta1/latest/

  33. abhishek Says:

    HEllo, could u help me , i did flex app and connected it to rails app, i’m generate the rxml pages in rails , but now i dont know how to run it from server with flex.

    i store both app(flex and rails) in 1 folder on server but it not conncted to rails. it shows error that

    faultCode:Client.Error.MessageSend faultString:’Send failed’ faultDetail:’Channel.Security.Error error Error #2048: Security sandbox violation: file:///C:/Documents and Settings/comp-27/Desktop/temp/jhakkastv.swf cannot load data from http://localhost/flex/messagebroker/amf. url: ‘http://localhost/flex/messagebroker/amf’‘

    i gave path in mxml page httpservice url”http:localhost:3000/videos/feed” and it generate rxml page in view(feed.rxml) but not working on main server

    could u give ur cell number my cell number is: 9921096876

    thanks you

  34. wikiwiki Says:

    Oh god! I GOT IT!!!!!

    Thanks!!!!!

    Thank you very much!!!!!!!!

  35. Swadba Says:

    Congrats on an excelent Toturial

  36. July Says:

    celebrity scandal free celebrity sex tapes women celebrities free celebrity porn celebrity sedu hairstyles celebrity feet celebrity wallpapers robbs celebrity page celebrity nudes celebrity sex scenes

  37. sl4v3r Says:

    Hi, when I click in submit, i have the error:

    URL: http://localhost:3000/reviews/create"]
       at mx.rpc::AbstractInvoker/http://www.adobe.com/2006/flex/mx/internal::faultHandler()[E:\dev\3.0.x\frameworks\projects\rpc\src\mx\rpc\AbstractInvoker.as:216]
       at mx.rpc::Responder/fault()[E:\dev\3.0.x\frameworks\projects\rpc\src\mx\rpc\Responder.as:49]
       at mx.rpc::AsyncRequest/fault()[E:\dev\3.0.x\frameworks\projects\rpc\src\mx\rpc\AsyncRequest.as:103]
       at DirectHTTPMessageResponder/errorHandler()[E:\dev\3.0.x\frameworks\projects\rpc\src\mx\messaging\channels\DirectHTTPChannel.as:343]
       at flash.events::EventDispatcher/dispatchEventFunction()
       at flash.events::EventDispatcher/dispatchEvent()
       at flash.net::URLLoader/redirectEvent()

    PLEASE help!

  38. Regenbekleidung Says:

    Thanks for all this informations.

  39. limousine nj Says:

    Thanks, nice tutorial! One thing isnt working for me: when I click Submit the new record I entered doesnt show up in the grid. Database okay and the grid is indeed updated…

  40. nj car service Says:

    Thanks for all this informations. Seems to be helpful.

  41. Tells Says:

    Thanks a lot for your very helpful informations, i will read now immidiately Part two :-) Best regards from Stuttgart SUE

  42. Jesse Says:

    I tried this example using separate server for flex part and ruby back-end. The first part of the tutorial works, (after adding crossdomain.xml of course), but the second part, adding data submission does not. I get the following error on the server

    ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken): /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/request_forgery_protection.rb:79:in `verify_authenticity_token’ /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/filters.rb:469:in `send!’ /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/filters.rb:469:in `call’ . . . I am a bit new to ruby, but not to flex. Any advice?

  43. Training Man Says:

    Hi – thought I’d say thanks v much for the Ruby on Rails / Flex tutorials before moving on to Part 2. Looks useful thus far.

  44. Peter Says:

    Jesse, that’s the forgery protection in Rails. Comment protect_from_forgery in apllication.rb and you should be ok.

  45. Flge Kuba Says:

    Ive had some problems to implement it, but now it works very nice. Really great guide!! Thanks for writing it down for us! I love people who share knowledge! It helped me very much, thanks again!!

  46. agkekrgmgy Says:

    Hello my friend, your site is very good! http://wduwcyjmwnzgm.com

Leave a Reply