Feb 11 2008

Server push with Ruby on Rails using Flex, JRuby, and BlazeDS

Tag: ActiveMQ, ActiveMessaging, Flex, Flex and Rails, JRuby, Messaging, Server Push, blazedsDerek Wischusen @ 5:32 am

In a previous post I discussed how you can integrate Flex and Scala/Lift using BlazeDS.  In this post I’ll show that it’s also possible to get Rails running on BlazeDS using JRuby.

Here is what I am using for this example:

You don’t really need Netbeans, but I’ve found that it makes things a bit easier.

For this example I am going to assume you have a basic understanding of Flex and Rails.  That said, if anyone has a question, not matter how basic, please feel free to ask.

Here are the source files if you want to follow along:

—– 

Ok, first lets get the Rails app set up.

1. Create a new Rails app called RoRBlaze.

2. Generate a controller called Greeting with an index view.  i.e.,

> ruby script/generate controller Greeting index

3.  Open up your newly generated greeting.rb file and add the following code:

class GreetingController < ApplicationController
  include Java
  import "flex.messaging.MessageBroker"
  import "flex.messaging.messages.AsyncMessage"
  import "flex.messaging.util.UUIDUtils"

  @@msgBroker = MessageBroker.getMessageBroker(nil)
  @@clientID = UUIDUtils.createUUID()

  def hello
    @msg = AsyncMessage.new()
    @msg.setDestination("notifications")
    @msg.setClientId(@@clientID)
    @msg.setMessageId(UUIDUtils.createUUID())
    @msg.setTimestamp(Time.new.to_f)
    @msg.setBody("Hello from Rails")
    @@msgBroker.routeMessageToService(@msg, nil)
    render :text => "Greeting Sent"
  end
end

4. Open view/greeting/index.rhtml and add a button to it like so,

<%=button_to "Send Greeting to Flex", :action=>"hello" %>

5. Go to the BlazeDS folder and  locate the following two .jar files in tomcat\webapps\blazeds\WEB-INF\lib:

  • flex-messaging-common.jar
  • flex-messaging-core.jar

6. Copy these .jar files into the lib folder in your Rails app (keep this folder open, you’ll need the more of the .jars in a moment).

7. In your Rails app open up config/environment.rb and add the following to the bottom of the file:

Dir["#{RAILS_ROOT}/lib/**/*.jar"].each do |jar|
  require jar
end

Alright, thats pretty much all of the Ruby code for this simple example.  Now we need to use the Goldspike Rails plugin to modify our Rails app so that it can run in a Java server (like Tomcat or Jetty or Glassfish, etc)

8.  From a command line, go to the root of your Rails app and install the Goldspike plugin:

> ruby script/plugin install http://jruby-extras.rubyforge.org/svn/trunk/rails-integration/plugins/goldspike

9. WARify you Rails app using the following rake command:

> rake war:standalone:create

Assuming that Goldspike did its job, you should now have a folder called WEB-INF in the root of you Rails app.  We need to add a few file to this folder to get BlazeDS working.

10. Copy the .jars from BlazeDS\tomcat\webapps\blazeds\WEB-INF\lib into RoRBlaze\WEB-INF\lib

11. Copy the folder BlazeDS\tomcat\webapps\blazeds\WEB-INF\flex into RoRBlaze\WEB-INF

12. Open up the web.xml file in blazeds\WEB-INF and merges its contents into the web.xml file in RoRBlaze\WEB-INF.  Click here to see what the final file should look like.

13. Open up RoRBlaze\WEB-INF\flex\messaging-config.xml and modify it so that it looks like this (click to view the file).  The key thing to note here is that we added a messaging destination called “notifications”.  This is the destination that the Greeting controller publishes to and it is the destination that our Flex app will subscribe to.

14. Open up RoRBlaze\WEB-INF\flex\services-config.xml and modify it so that it looks like this (click to view the file).  The key thing to notice in this file is that we defined a streaming channel called my-streaming-amf that BlazeDS will use to push messages over a persistent, streaming HTTP channel.

That’s it for the Rails app.  Now let’s create the Flex app.

—–

1. Create a new Flex Project (File -> New -> Flex Project)

2. Fill in the rest as follows:

  • Project name: RoRBlaze
  • Application type: Web Application
  • Application server type: J2EE
  • Use remote object access service: check this
  • Root folder: RoRBlaze  (the root folder of your Rails app)
  • Root URL: http://localhost:8080/RoRBlaze/
  • Context root: /RoRBlaze
  • Output folder: RoRBlaze\public
  • Output folder URL: http://localhost:8080/RoRBlaze

3. Open up RoRBlaze.mxml and edit it like so:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="vertical"
	creationComplete="consumer.subscribe()">

    <mx:Script>
        <![CDATA[
          	import mx.messaging.events.MessageEvent;

            private function messageHandler(message: MessageEvent): void
            {
                pushedMessage.text = message.message.body as String;
            }
        ]]>
    </mx:Script>

    <mx:Consumer
    	id="consumer"
    	destination="notifications"
    	message="messageHandler(event)"
    	channelConnect="trace(event)"
        channelFault="trace(event)"
        fault="trace(event)" />

    <mx:TextInput id="pushedMessage" width="300"/>
</mx:Application>

That’s it for the Flex app.  Let’s test everything out.

—–

1. Open a terminal and go to the root of your Rails app.  Then use Goldspike to boot up your Rails app in a Jetty server:

> rake war:standalone:run

In a few short seconds your Rails app should  be up and running.

2. Launch the Flex app.

3.  Open a browser and enter the following URL: http://localhost:8080/RoRBlaze/greeting

You should see a single button that says “Send Greeting to Flex”

4. Click the button.

Upon clicking the button you should see the browser display “Greeting Sent” and you should see “Hello from Rails” appear in the text input in your Flex app.

That’s it.  Assuming that everything worked properly, the Rails app should have pushed an AMF encoded message to Flex using a persistent streaming HTTP channel created by BlazeDS.

One importatant thing to take note off is that this technique could be useful to you even if you aren’t planning on using Flex/Flash as your presentation layer.  You could use a Juggernaut style approach and push messages from Rails to an embedded Flash player whose only job is to pass those messages along to the browser.

This example demonstrates a very simple way to integrate Flex, Rails, and BlazeDS.  I think the ideal way to integrate these technologies would be to use the ActiveMessaging plugin for Rails, since both ActiveMessaging and BlazeDS have JMS adapters which they could use to integrate with a more robust messaging system like ActiveMQ.  If I can find some time in the near future, and if there is any interest, I’ll do a follow up post on this.


Jul 28 2007

Publish\Subscribe Messaging with Flex and Rails using Apache ActiveMQ, ActiveMessaging, and STOMP

Tag: AS3, ActiveMQ, ActiveMessaging, Flex and Rails, Messaging, STOMP, Server PushDerek Wischusen @ 6:09 pm

This will be the first in a series of posts where I’ll cover how you can do publish\subscribe and other messaging methods with Flex and Rails using ActiveMQ, the Rails ActiveMessaging plugin, and the STOMP protocol to get them all communicating. In this post I will describe how to create a simple Flex consumer that receives messages from a Rails app that serves as the producer.

Before we get to that, let’s start with a brief description of the technologies involved. The following descriptions are from the technologies’ respective websites:

Apache ActiveMQ

Apache ActiveMQ is the most popular and powerful open source Message Broker.

Apache ActiveMQ is fast, supports many Cross Language Clients and Protocols and many advanced features while fully supporting JMS 1.1 and J2EE 1.4. Apache ActiveMQ is released under the Apache 2.0 License.

ActiveMessaging

ActiveMessaging is an attempt to bring the simplicity and elegance of rails development to the world of messaging. Messaging, (or event-driven architecture) is widely used for enterprise integration, with frameworks such as Java’s JMS, and products such as ActiveMQ, Tibco, IBM MQSeries, etc.

And, lastly the protocol that we’re going to use to tie everything together:

STOMP

The Stomp project is the Streaming Text Orientated Messaging Protocol site (or the Protocol Briefly Known as TTMP and Represented by the symbol :ttmp).

Stomp provides an interoperable wire format so that any of the available Stomp Clients can communicate with any Stomp Message Broker to provide easy and widespread messaging interop among languages, platforms and brokers.

Now that you know a little something about technologies that we will be using (I am assuming that you probably already know about Flex and Rails), let’s build something.

Prerequisites:

  • Ruby 1.8.6
  • Rails 1.2.3
  • Java 1.5.0_07+
  • MySQL (or any other database that works with Rails migrations)

Here are the source files if you would like to follow along.

Source Files:

Creating the Rails App

Let’s kick things off by creating the Rails producer app. It’s going to be a really small app called sales_report that is used to capture and distribute simple sales data.

1. Crack open the database of your choice and create a database called sales_report. For example,

$ CREATE DATABASE sales_report

2. Create the app

$ rails sales_report
$ cd sales_report

3. Generate your sale model

$ script/generate model sale

4. Open up the 001_create_sales.rb migration that you just created in db/migrate and add the following

  def self.up
    create_table :sales do |t|
      t.column :customer, :string
      t.column :product, :string
      t.column :quantity, :integer
    end
  end

5. Open up config/database.yml and configure it for your database. For example,

development:
    adapter: mysql
    database: sales_report
    username: root
    password: your_password_here
    socket: /tmp/mysql.sock

6. Run the migration rake task to create the sale table that you defined in migration file above.

$ rake db:migrate

7. Generate the sales controller.

$ script/generate controller sales index

8. For this application,we really just need to be able to produce new sales records, so Rails scaffolding will work just fine. Open up sales_controller.rb and make it look like this:

class SalesController &lt; ApplicationController
  scaffold :sale
end

9. That’s all for the basic Rails app. Now it’s time to start working with ActiveMessaging. So, let’s install the plugin and a couple of gems that it uses.

$ gem install daemons
$ gem install stomp
$ script/plugin install http://activemessaging.googlecode.com/svn/trunk/plugins/activemessaging

10. Now that we have everything installed, let’s create an ActiveMessaging processor. We don’t actually need the processor for this tutorial, but it generates some other files that we do need.

$ script/generate processor sale
create  app/processors
create  app/processors/sale_processor.rb
create  test/functional/sale_processor_test.rb
create  config/messaging.rb
create  config/broker.yml
create  app/processors/application.rb
create  script/poller

11. Open up config/broker.yml and configure the stomp adapter as follows:

development:
   adapter:
   stomplogin: ""
   passcode: ""
   host: localhost
   port: 61613
   reliable: false

12. Now open up config/messaging.rb and specify the destination for the queue, like so

ActiveMessaging::Gateway.define do |s|
  s.destination :sale_queue, '/queue/Sale'
end

13. Almost done. The last step for the Rails app is to create an Observer that watches the Sale model to see when a new sale is saved to the database and then publishes it to the queue that you just set up.

$ script/generate observer sale

14. Now edit app/model/sale_observer.rb as follows.

require 'activemessaging/processor'
class SaleObserver &lt; ActiveRecord::Observer
  include ActiveMessaging::MessageSender
  publishes_to :sale_queue
 
  def after_save(sale)
    record = sale.to_xml
    publish :sale_queue, record
  end
end

This class watches the Sale model. When a new sale record is saved to the database the after_save method is called. This method takes the new sale ActiveRecord instance converts it to XML and publishes it to the sale_queue.

15. Finally, boot up the server.

$ script/server

Installing ActiveMQ
Installing and running ActiveMQ is dead simple.

1. Just go and grab one of the latest snapshots from here.

2. Download it and unzip it.

3. Navigate to activemq/bin and run activemq.

4. If you need additional instruction, check out this page.

5. Once you have ActiveMQ up and running, proceed to the next section on building the Flex app.

The Flex App and the STOMP AS3 Client
To get Flex talking with ActiveMQ we are going to be using the STOMP protocol. When I first started looking into ActiveMQ I came across this ActionScript 3 STOMP client developed by Richard Jewson. I’ve since update the library substantially so that it implements the majority of the STOMP protocol. For now, you can get the source for the STOMP library by downloading the source for the Flex app. I am going to submitting this code to the STOMP project on codehaus.org, so in the future you will be able to grab updates from there.

For the Flex app we’ll just focus on the code that is needed to connect to ActiveMQ via STOMP and consume the xml that Rails is publishing. To makes things a bit easier, we’ll start with the completed Flex and just walkthrough the code. If you haven’t already download the source for the Flex app. To see what the Flex app looks like click here. As you can see it’s pretty much just a data grid that is used for displaying the sale info.

So, here is the important code, which is all inside the script tags in the Flex app:

[Bindable]
private var sales : ArrayCollection = new ArrayCollection();
 
private var stomp : STOMPClient = new STOMPClient();
private var queue : String = "/queue/Sale";
 
private function init () : void
{
	stomp.connect("localhost", 61613);
	stomp.subscribe( queue );
 
	stomp.addEventListener(MessageEvent.MESSAGE, handleMessages);
	stomp.addEventListener(ReceiptEvent.RECIEPT, handleReceipts);
	stomp.addEventListener(STOMPErrorEvent.ERROR, handleErrors);
 
}
 
private function handleMessages(event : MessageEvent) : void
{
	var incomingMsg : XML = XML(event.message.body);
	var processedSale : ObjectProxy = simplerXMLDecoder(incomingMsg);
	orders.addItem(processedSale);
}
 
private function handleReceipts (event : ReceiptEvent) : void
{
	trace ("Got receipt: " + event.receiptID)
}
private function handleErrors (event : STOMPErrorEvent) : void
{
	trace ("Error: " + event.error.body)
}
 
private function simplerXMLDecoder (x : XML) : ObjectProxy
{
	var xdoc : XMLDocument =  new XMLDocument();
	xdoc.ignoreWhite = true;
	xdoc.parseXML(x.toXMLString());
	var decoder : SimpleXMLDecoder =  new SimpleXMLDecoder(true);
	return decoder.decodeXML(XMLNode(xdoc.firstChild)) as ObjectProxy;
}

Here’s what’s going on in this code.

  • Up near the top we create a new STOMPClient
  • Directly below we specify the destination for the queue that we will be subscribing to, which is the same destination that we specified in messaging.rb above.
  • In the init() method, which is called when the application loads, we connect to the STOMP broker (ActiveMQ) and then subscribe to the queue.
  • We then set up listeners to listen for messages from ActiveMQ.

All of the real action is happening in the handleMessages method.

  • The handleMessages method gets called when the Rails app sends out the xml for a new sale.
  • When a new message is received we take the body of the message (which is the xml from Rails) and use the XMLDecoder class to turn it into a bindable ObjectProxy.
  • Finally, the new sale is added to the sales ArrayCollection, which is the data provider for the data grid in the Flex app.

Getting Everything Up and Running

Alright, now we are actually ready to run something. Assuming that the Rails app and ActiveMQ are still running, all that we need to do is launch the Flex app. You can either build the app yourself from the source files, or you can go in to the source files, open the bin folder and launch StompSalesReport.html.

Now, open a browser and navigate to http://localhost:3000/sales/new

You should see our spartan, but functional, scaffolded interface. Enter some product info and click Create.
Rails Sales Report

Now if you switch back to Flex app, you should see the following:

Flex Sales Report

Pretty exciting stuff. Immediately after the sale was saved to the database, the SaleObserver published it to the queue, where ActiveMQ pushed it out to the Flex app.

One last little tidbit. If you change the code in init() method in the Flex app so that it looks like this:

private function init () : void
{
        var ch : ConnectHeaders =  new ConnectHeaders();
	ch.clientID = "MYTOTALLYUNIQUECLIENTID";
	stomp.connect("localhost", 61613, ch);
 
	var sh : SubscribeHeaders = new SubscribeHeaders();
	sh.amqSubscriptionName = "MYSUBSCRIPTION";
	stomp.subscribe( queue, sh );
 
	stomp.addEventListener(MessageEvent.MESSAGE, handleMessages);
	stomp.addEventListener(ReceiptEvent.RECIEPT, handleReceipts);
	stomp.addEventListener(STOMPErrorEvent.ERROR, handleErrors);
}

By passing a client-id header on connect and a subscriptionName header on subscribe we create what is known as a durable subscriber.

If you compile the Flex app, launch it and then close it. Then go in back to the Rails app and create a new sale, relaunch the Flex app and you should immediately see the sale show up.


Whew! That’s it. This post was way too long. I am thinking that it may be easier to cover this stuff in a screencast. Let me know in the comments if you think a screencast would be a good idea.

As always, let me know if you have any questions.


Jun 14 2007

Flex and RESTful Rails tutorial en francais

Tag: Flex and Rails, tutorialDerek Wischusen @ 9:03 pm

If you are interested and in Flex and Rails, and you know french, then be sure to check out this tutorial by Laurent Bois.


Jun 13 2007

Tony Hillerson of effectiveUI talks about Flex and Rails

Tag: Flex and RailsDerek Wischusen @ 2:36 am

In a two part interview on the Flex Show, Tony Hillerson of effectiveUI discusses the benefits of working with Rails and why you might want to use Rails as the back-end for your Flex apps.

Part 1

Part 2


May 10 2007

O’Reilly’s latest State of the Computer Book Market contains good news for Rails and Flex

Tag: Flex and RailsDerek Wischusen @ 1:37 am

It’s good to see that interest in both of these frameworks continues to grow. Here is a quote from the article (bold added by me):

In the Web design and development area, it’s worth noting that Ruby on Rails has continued its blazing growth, but Ajax books have not. The decline of both PHP and ASP are striking. Flash and Dreamweaver are also down, but as noted above, awaiting the CS3 release. Flex is starting to show its muscle.

Click here to read the full article.


Feb 14 2007

A little less configuration, or eliminating the need for mappings in the remoting-config.xml file in WebORB for Rails

Tag: Flex and Rails, weborbDerek Wischusen @ 3:21 am

After reading this post on the Midnight Coders forum about a method for eliminating the need for mapping services in the remoting-config.xml file WebORB for PHP, and driven by my intense dislike of configuration, I thought I would see if the same thing is possible in WebORB for Rails. Turns out it is really easy.

Here is all you have to do:

    1. add endpoint="/weborb" to your RemoteObject definition.

    2. Make sure that the destination property on the RemoteObject matches the name of the service class that you want to call in Rails.

For example, if you had a service class in your Rails app called IssueService, here is what the RemoteObject would look like in Flex:

    <mx:RemoteObject id="issueService" destination="IssueService"
    		    endpoint="/weborb"
		    showBusyCursor="true"
		    result="event.token.resultHandler( event );"
		    fault="event.token.faultHandler( event );">
    </mx:RemoteObject>

That’s all you have to do. Now you don’t have to add any mappings to the remoting-config.xml file (note that you still need to keep the file because WebORB looks for it, you just don’t have to do anything with it), and you can get rid of the -services argument in your compiler options.

I’ve set up all of the services in one of my apps like this and everything seems to be working properly. Let me know if you encounter any issues with this, or if you have any questions.


Feb 05 2007

Amazon’s S3, Flex, and Rails

Tag: Flex and RailsDerek Wischusen @ 2:48 am

Alex MacCaw has just posted a screenshot of Aireo, an application that he is developing that allows you to access Amazon’s S3 data storage using a Flex/Apollo front-end and a Rails back-end. Here is a brief description taken from Aireo’s website:

Aireo in a nutshell:

  • Scalable: Aireo is built on Amazon’s S3 data storage service, allowing virtually unlimited storage space for very competitive prices.
  • Safe: Files have the option of being encrypted to military grade standards.
  • Accessible: You can access Aireo through WebDAV, FTP, a html interface and Apollo.
  • Flexible: Aireo can be accessed from all major operating systems, such as Windows, Mac and Linux.
  • Collaborative: Files can be quickly referenced and passed around a company as Aireo interfaces with your email system. Files can also be collaboratively edited. On top of this, Aireo allows file sharing with people outside the company if necessary.
  • Mobile: Aireo allows you to disconnect and travel, syncing your changes when you next go online. You can also access Aireo through a wireless enabled PDA.

Jan 27 2007

Sending Typed Value Objects from Flex to Rails using WebORB and the [RemoteClass] metadata tag

Tag: Flex and Rails, weborbDerek Wischusen @ 2:14 am

In Part 2 of the tutorials that I have been writing about the Issue Tracker sample app (view, source) I discussed how you can Get Typed Objects from Rails using [RemoteClass]. Now, with the latest version of WebORB, it is also possible send typed objects from Flex to Rails.

This means that you no longer have to use untyped objects or XML to send values from Flex to Rails. Now you can just pass typed value objects back and forth between Flex and Rails.

So now, in the Issue Tracker sample app, when an IssueVO is sent from Flex to Rails, because it is mapped to the Issue ActiveRecord class (using the process that is explained in Part 2), it automatically gets converted to an Issue ActiveRecord instance. If the value of the id attribute on the IssueVO matches an existing Issue ActiveRecord then WebORB will return that object, otherwise it will create a new ActiveRecord instance.

This makes it possible to simplify the updateIssue method as follows:

  def updateIssue(issue)
    issue.save
  end

Jan 13 2007

Part 4 – Flex Cairngorm/WebORB Issue Tracker Tutorial – Invoking ActiveRecord Methods Directly From Flex

Tag: Flex and Rails, tutorialDerek Wischusen @ 11:52 pm

This is the fourth post in a series that covers certain features of Issue Tracker sample app (view, source) that I added to the Flex RoR SDK.

The first post explained how to set up the application.

The second post covered how you can get WebORB for Rails to return typed objects to Flex using the [RemoteClass] metadata tag.

The third post covered how to use ActiveRecord Associations with WebORB.

This post explains how you can invoke ActiveRecord methods directly inside of a Flex client.

WebORB gives you the ability call ActiveRecord methods from inside of Flex. Here is all you have to do to make this happen:

1. To do this you first set up a RemoteObject in Flex just like you would for any other service. For example, the following code is from the Services.mxml file in flex_issue_tracker2 project:

<mx:RemoteObject id="userService" destination="userServiceImpl"
		    showBusyCursor="true
                       result="event.token.resultHandler( event );"
		    fault="event.token.faultHandler( event );">
</mx:RemoteObject>

2. Open up the remoting-config.xml file (located in C:\rails\rails_issue_tracker2\config\WEB-INF\flex) and map the RemoteObject directly to an ActiveRecord class. This is the mapping for the userService RemoteObject:

    <destination id="userServiceImpl">
        <properties>
            <source>User</source>
        </properties>
    </destination>

Now when you make a method call on the userService RemoteObject it as though you are making the call directly on the User ActiveRecord class. This makes it possible to do some interesting things, such as calling ActiveRecord dynamic finder methods directly on the userService, which is what is currently happening in the UserDelegate class in Flex:

package com.rxr.issuetracker.business
{
import mx.rpc.IResponder;
import com.adobe.cairngorm.business.ServiceLocator;

public class UserDelegate
{
	private var responder : IResponder;
	private var service : Object;

	public function UserDelegate(responder : IResponder)
	{
	      this.service = ServiceLocator.getInstance().getService( "userService" );
	      this.responder = responder;
	}

	public function loginUser(username : String, password : String) : void
	{
	      var call : Object = service.find_by_username_and_password(username, password);
	      call.resultHandler = responder.result;
	      call.faultHandler = responder.fault;
	}

	public function registerUser(username : String, password : String) : void
	{
	      var call : Object = service.find_or_create_by_username_and_password(username, password);
	      call.resultHandler = responder.result;
	      call.faultHandler = responder.fault;
	}
}
}

ActiveRecord dynamic finders are finder methods that are automatically generated by Rails based on the column names in the table that the ActiveRecord wraps. For example, the users table has three columns: id, username, and password. So, the User ActiveRecord class automatically generates a method called find_by_username, and a method called find_by_username_and_password, and so on. Click here to read an article that provides an in-depth explanation of how dynamic finders work.

As you can see, there are two dynamic finders that are currently being used in the UserDelegate class: find_by_username_and_password(username, password); in the loginUser method which finds an existing user, and find_or_create_by_username_and_password(username, password); in the registerUser method which creates a new user if it does not find one that matches the provided username and password.

Ok, now that you know how invoke ActiveRecord methods inside of Flex I should note that I think that you should only do this where it really makes sense to do so. The obvious drawback to this approach is that you have to make a call to the server for each method that you invoke. In general, it is best to keep this type of logic in a server-side service class (like the ProjectService and the IssueService). I’ve only included this functionality in Issue Tracker Sample app to show that it is possible. I plan to remove this code in the next update of the application and move into a UserService class.


Jan 09 2007

Part 3 – Flex Cairngorm/WebORB Issue Tracker Tutorial – Using ActiveRecord Associations with WebORB

Tag: Flex and Rails, tutorialDerek Wischusen @ 2:13 am

Ok, I am finally back from vacation.

This is the third post in a series that covers certain features of Issue Tracker sample app (view, source) that I added to the Flex RoR SDK.

The first post explained how to set up the application.

The second post covered how you can get WebORB for Rails to return typed objects to Flex using the [RemoteClass] metadata tag.

This post covers how to use ActiveRecord Associations with WebORB.

What is an ActiveRecord?

For those of you who are new to Rails, let’s start with a quick discussion of ActiveRecords and ActiveRecord Associations. The ActiveRecord class in Rails is an implementation of Martin Fowler’s Active Record design pattern. Martin defined an Active Record as:

An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.

The Rails ActiveRecord class obviously does a lot more than this, but for this tutorial all you need to know is that an ActiveRecord is an object that wraps a table in a database.

What is an ActiveRecord Association?

So, what is an ActiveRecord Association? Well, as you can probably guess, it is association between ActiveRecord objects, or in other words it is an association between tables in a database.

Rails Conventions

To understand how ActiveRecord associations work we need to cover a couple of Rails conventions. As you might know, part of the power of Rails framework is that it favors convention over configuration. This means that if you adhere to Rails conventions it will take less code to get your apps up and running.

Here are two Rails conventions that are relevant to this discussion:

  • A tables primary key column should be named id.
  • Foreign keys should be named <class>_id.
  • For example, in the Issue ActiveRecord class in the Issue Tracker Sample App there is a attribute named project_id. This attribute contains the value in the id attribute for the project that the issue belongs to.

    foreign key convention

    Types of Associations

    There are several different types of relationships that you can create between tables using ActiveRecord Associations. They include:

  • has_one – one to one
  • has_many or belongs_to  - one to many
  • has_and_belongs_to_many – many to many
  • You can use ActiveRecord Associations to quickly create complex relationships. For example,

    has_many :contributors, :through => :contributions, :uniq => true

    This tutorial focuses on the has_many association.

    Creating an Active Record Association

    To see how to create a has_many association between to two ActiveRecord objects, open up the Project class. The class file is located in C:\rails\rails_issue_tracker2\app\models.

    Inside the Project class file you will see the following:

    class Project < ActiveRecord::Base
          has_many :issues, :dependent => :delete_all
    end
    

    This tiny piece of code does a couple of things. The first half (has_many :issues) creates a has_many association between the Project ActiveRecord and the Issue ActiveRecord. The second half (:dependent => :delete_all) states that the issues associated with a project are dependent on that project and that they should be deleted if the project is deleted. In other words, if you a delete a given project, this piece of code tells Rails that all the issues associated with the project should be deleted also.

    Now, to see how we can put this association to work, open up the ProjectService class. The ProjectService class file is located in C:\rails\rails_issue_tracker2\app\Services.

    In the ProjectService class you will see the following method:

    def getProjects(user_id)
         projects = Project.find(:all, :include => [:issues],
     				    :conditions => ['user_id = ?', user_id])
    end
    

    Pay special attention to this bit of code: :include => [:issues]. This argument tells the find method that for each project it finds, it should also go out and get all of the issues that are associated with that project. Rails knows how to do this because of the conventions that I discussed above. For each project that the find method returns, Rails inspects the value in the id column, then it goes out and finds all of the issues that have this value in the project_id column. Now each project will have an attribute named issues that contains an array of all the issues that are a part of that project.

    So, now with this code in place, when you run the Issue Tracker Sample App and log in, the GetProjectsCommand gets executed on the Flex side of the app. This command calls the getProjects method in Rails. The getProjects methods finds all of the projects where the value in the user_id column equals the user_id for the current user. At the same time, the find method goes out and finds the issues for each project and packs them up into an array. WebORB wraps all of this up and returns the projects to Flex as ProjectVOs using the [RemoteClass] metadata tag.

    By default, WebORB takes objects that are typed as arrays in Rails and sends them to Flex as arrays. So, the issue array that is part of each project ActiveRecord instance in Rails is sent to Flex as an array. This is fine for most purposes, but if you want to be able to do databinding then you need to use a collection of some sort (e.g., ArrayCollection, XMLCollection, etc). My simple solution to this problem was to write a setter function that takes the issues array and stores it in a ArrayCollection named issuesCollection. Now you can bind your components to the issueCollection and they will be automatically updated when the collection is updated.

    package com.rxr.issuetracker.vo
     {
     	import com.adobe.cairngorm.vo.IValueObject;
     	import mx.collections.ArrayCollection;
      	[Bindable]
     	[RemoteClass(alias="com.rxr.issuetracker.vo.Project")]
     	public class ProjectVO implements IValueObject
     	{
     	         public var id : int;
      		public var user_id : int;
      		public var title : String;
      		public var issueCollection : ArrayCollection = new ArrayCollection();
      		public function set issues ( value : Array ) : void
     		{
     			issueCollection = new ArrayCollection(value);
     		}
    	  }
     }
    

    ActiveRecord Association in Action

    When you run the Issue Tracker Sample App and log in the Flex app runs the GetProjectsCommand, which calls the getProjects method in the ProjectsService (see above) in Rails. Now that there is a has_many association between the Project ActiveRecord and the Issue ActiveRecord, this single service call returns all of the projects for a given user, and all of the issues associated with each project. So now you can take the result of this single service call (see below) and cache it on the client, which will significantly reduce the number of calls that you have to make to server for the rest of the session.

    active record association

    As always, drop me a line if any of this is unclear or incorrect.


    Next Page » Get viagra prescription
    Get viagra
    Prescription propecia
    Valium without prescription
    Buy levitra
    Generic cialis uk
    Xanax with no prescription
    Tramadol no prescription required
    Viagra to buy
    Buy xanax overnight
    Buy cialis online from canada
    Discount viagra online
    Valium generic
    Buy tramadol hydrochloride
    Xanax 1 mg dose
    Free samples of cialis
    Tramadol for sale
    Best way to buy viagra online
    Prescription valium
    Cialis discount price
    Australia viagra online
    Order tramadol cod
    Cheap xanax for sale
    Propecia price
    Overnight tramadol no prescription
    Generic xanax xr
    Phentermine 37.5mg
    Viagra in france
    Cheap phentermine without prescription
    Xanax 1mg side effects
    Cheap viagra online without prescription
    Cheap propecia without prescription
    Viagra no prescription online
    Levitra price
    Viagra tablets for sale
    No prescription valium
    Levitra online
    Purchase phentermine without prescription
    Buy cialis in the uk
    Pfizer viagra price
    Ordering propecia from canada
    Phentermine canadian pharmacy
    Cheap levitra no prescription
    Best prices for cialis
    Propecia price australia
    Cialis 10mg side effects
    Buy brand name viagra
    Low price viagra
    Purchase cialis without a prescription
    Viagra dosage information
    Brand viagra cheap
    Buy pfizer viagra without prescription
    Valium no rx
    Buy female viagra without prescription
    Best viagra alternative
    Generic xanax no prescription
    Tramadol without prescription overnight delivery
    Prednisone dosages
    Viagra pills for sale
    Levitra online buy
    Buying viagra in london
    Buy cialis viagra
    Where to buy levitra online
    Generic cialis overnight
    Purchase viagra online without prescription
    Xanax overnight cod
    Buy levitra online canada
    Buy generic cialis online
    Online prescription tramadol
    Buy generic propecia uk
    Purchase xanax
    Tramadol prescription online
    Cialis 20 mg dosage
    Xanax bars side effects
    Viagra 50mg side effects
    Where to buy cialis online
    Viagra indian pharmacy
    Phentermine online uk
    Viagra india price
    Buying cialis
    Order xanax online
    Genuine viagra online
    Propecia generic cost
    Cheap generic viagra
    Order xanax cod
    Viagra online cheap
    Best viagra dose
    Cialis price
    Cheap tramadol cod
    Best levitra prices
    Valium cheapest
    Levitra 20mg
    Blood pressure and prednisone
    Cialis uk sales
    Viagra canada prices
    Authentic phentermine 37.5
    Real phentermine without prescription
    Buy generic valium
    Best price cialis
    Cheap levitra uk
    Discount viagra pills
    Generic xanax
    Cialis 20mg side effects
    Cheap cialis india
    Best way to take tramadol
    Valium online uk
    Buy viagra uk online
    Cheap tramadol overnight delivery
    Phentermine diet pills without prescription
    Viagra online without prescription reviews
    Tramadol dosage
    Cheap xanax bars
    Cheapest online cialis
    Canada viagra no prescription
    Cialis for sale
    Phentermine purchase online
    Low price cialis
    Canada viagra
    Purchase tramadol without prescription
    Generic viagra 100mg
    Viagra professional online
    Viagra generic cheap
    Buying cialis online without a prescription
    Propecia cost
    Cheap cialis
    Buying xanax online without prescription
    Buy phentermine no rx
    Where to buy propecia in canada
    Order cheap phentermine
    Order phentermine online no prescription
    Prescription viagra uk
    Buy viagra in england
    No prescription cialis online
    Viagra purchase uk
    Viagra ordering
    Prescription free viagra
    Buy tramadol overnight
    Buy generic phentermine online
    Xanax 0.5 mg
    Xanax no prescription required
    Buy propecia online without a prescription
    Buy viagra online uk no prescription
    Buy xanax canada
    Viagra cheapest
    Order prednisone no prescription
    Viagra online uk
    Buy tramadol cod
    Ordering cialis online
    Phentermine cheap online
    Cialis cialis
    Tramadol cheapest
    Where to buy viagra in england
    Cialis 20mg
    Xanax no prescription overnight
    Propecia cheap
    Order viagra without prescription
    Valium online pharmacy
    Generic tramadol
    Mail order phentermine
    Buy propecia cheap
    Buy viagra 100mg
    Cheap cialis pills
    Get tramadol prescription
    Cialis order online
    Valium 10 mg
    Viagra fast delivery
    Propecia uk prices
    Propecia 1mg generic
    Cialis canada no prescription
    10mg valium effects
    Viagra buy online no prescription
    Viagra price canada
    Brand name cialis
    Where to buy viagra online
    Cialis dosage 20mg
    Prednisone tablets
    Viagra pharmacy uk
    Purchase tramadol online
    Prednisone 20mg side effects
    Order tramadol online cod
    Cialis purchase online
    Xanax buy uk
    Viagra canadian online pharmacy
    Cialis prescription cost
    Buy valium cheap online
    Buying viagra in new zealand
    Online prescriptions xanax
    Cialis side effects
    Cheapest place to buy viagra online
    Buying valium in spain
    Prescription phentermine online
    Buy cheap viagra online uk
    Xanax generic dosage
    Generic viagra for sale
    Phentermine with no prescription
    Tramadol free shipping
    Fedex tramadol
    Prescription viagra canada
    Phentermine buy uk
    Buy viagra online in australia
    Valium drug side effects
    Prednisone online
    Propecia information
    Levitra online cheap
    Tramadol cod delivery
    Phentermine 37.5 wholesale
    Viagra discount coupons
    Buy viagra online cheap
    10mg prednisone
    How to buy phentermine online
    Buy phentermine online without prescription
    Buy viagra from canada
    Viagra canada online
    Phentermine buy australia
    Xanax bars effects
    How to buy valium without a prescription
    Xanax 1mg
    Phentermine hcl no prescription
    Phentermine without a prescription
    Phentermine canada no prescription
    Valium online overnight
    Viagra prescription
    Side effects of viagra
    Where to buy phentermine cheap
    Where to buy cialis without prescription
    Overnight delivery viagra
    Viagra canada mastercard
    Cialis medication
    Cialis over the counter
    Low cost cialis
    Dose of xanax
    Buy cialis uk
    Viagra in the philippines
    Viagra without prescription uk
    Overnight xanax delivery
    Buying viagra online
    Cialis soft tabs online
    Best price tramadol
    Discount viagra usa
    Propecia usa
    Phentermine 37.5 pills
    Xanax price per pill
    Xanax no rx
    2.5mg cialis
    Generic viagra super active
    Buy cialis brand
    Viagra sale uk
    Where can i buy viagra without prescription
    Xanax online cheap
    Buy xanax cheap online