Jan 09
Part 3 – Flex Cairngorm/WebORB Issue Tracker Tutorial – Using ActiveRecord Associations with WebORB
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.
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:
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.

Types of Associations
There are several different types of relationships that you can create between tables using ActiveRecord Associations. They include:
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.

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

January 9th, 2007 at 4:15 pm
[...] This is a pretty good series of articles really, they cover the basics of using Active Records and Active Record Associations in RoR and setting up your MySQL client and how to use the Remote Object with Flex 2 and RoR. Part 3 [...]
January 17th, 2007 at 10:17 pm
Thanks for the great series of articles.
How could you extend this further in rails?
What if the issues class also had a one to many association with another table.
Could the ‘find’ go down and retrieve the associated records from that table?
January 19th, 2007 at 6:04 pm
I imagine has_one and belongs_to are similar? Or does webORB return an less-nested array for those?
Any chance you’ll cover how classes are passed through webORB? I have some confusion about this, eg:
class Foo
def Bar
return “Baz”
end
def self.Bar
return “Boo”
end
end
…(now, in AS)…
Foo.Bar(); // = “Boo”
f = new Foo();
f.Bar(); // still = “Boo” ??
I’m wondering how things map.
– cheers,
Robbie
January 20th, 2007 at 9:53 pm
@Bruce – you could add a has_many association to the issues class (e.g., has_many :attachments), but the Project.find statement is not going to go down and retrieve those associated tables. Right now this statement retrieves all of the issues that are associated with a project in one query because of this argument :include => [:issues]), which tells the find that we want to use eager loading. You can only use eager loading to go out and get tables that are associated with the model class that is performing the query.
@Robbie – it is my understanding that WebORB first checks if there is an instance method (e.g., def Bar) that matches the name of the method being called in AS then, if there is not, it checks to see if there a class method (e.g., def self.Bar) that matches the name. You can read more about this here: http://www.themidnightcoders.com/forum/default.aspx?g=posts&t=116
January 30th, 2007 at 2:51 pm
Hi Derek,
Great article!! Thanks for your time in reading my post below …
I would like to understand if WebORB ignores associations that are not loaded.
so let’s say the project model looks like:
class Project :delete_all
has_many :tasks, :dependent => :delete_all
end
and the ProjectService method looks like this:
def getProjectAndIssues(project_id, user_id)
project = Project.find_by_id( project_id, :conditions => ['user_id = ?', user_id])
issues = project.issues #deliberately load issues in a separate step
end
In other words, in the getProjectAndIssues I am interested only in the Project and its Issues. Also I deliberately have loaded the issues in a separate step in the method
My questions are:
1) Will the project and its issues get sent to the Flex client?
2) Will WebORB leave the has_many :tasks association untouched?
3) Is WebORB intelligent enough to make sure that unloaded associations are left undisturbed and only the loaded associations are sent to the client?
January 30th, 2007 at 2:52 pm
the model should look like this:
class Project :delete_all
has_many :tasks, :dependent => :delete_all
end
January 30th, 2007 at 2:53 pm
sorry some how the model is not getting reflected properly for issues, so i will just write it out in words:
Project has many issues and has many tasks
January 31st, 2007 at 2:17 am
Hi Karthik,
As it is currently written, your getProjectAndIssues method would only return the issues that are associated with a given project.
If you do not use eager loading (e.g., :include =>[:issues]) when calling Project.find(), then the associated issues will not be sent over as part of the project.
Derek
January 31st, 2007 at 9:58 am
[...] Part 3 – Flex Cairngorm/WebORB Issue Tracker Tutorial – Using ActiveRecord Associations with WebORB [...]
February 14th, 2007 at 6:46 pm
I get the dreaded “unitialized constant ArrayCollection” error when sending the ProjectVO to Rails from Flex unless I do not instantiate the issueCollection variable.
ie
public var issueCollection : ArrayCollection;
instead of:
public var issueCollection : ArrayCollection = new ArrayCollection();
Is there a standard way of making this work in both directions?
February 15th, 2007 at 3:34 pm
Hi Damon,
I’ve not tried this yet, but you could write a getter that converts the ArrayCollection to an Array.
e.g.,
public function get issues () : Array
{
return issueCollection.toArray();
}
February 16th, 2007 at 9:29 pm
Thanks Derek. The problem is that issueCollection is still a public property and weborb complains when the object is passed to Rails. May I’m missing something.
March 15th, 2007 at 11:03 pm
Any answer to Damon’s question? I’m getting the “unitialized constant ArrayCollection†error from weborb service also. It’s borking on the ArrayCollections in my VOs. What’s weird is that Derek’s VO’s also has public fully-instantiated ArrayCollections but his clearly works.
For example in his ProjectVO.as we see:
public var issueCollection : ArrayCollection = new ArrayCollection();
I have something just like this in my ContactVO.as:
public var addressCollection : ArrayCollection = new ArrayCollection();
And it borks!
Is their a config setting somewhere that’ll tell weborb to ignore ArrayCollections? Not sure what I’m doing different than Derek here…
Thanks for any help
- TC
March 16th, 2007 at 1:28 am
Hi Damon, TC –
The way I originally had it set up only works when you are getting typed VOs from WebORB, not when you are sending typed VOs to WebORB.
If you are planning to send typed VOs from Flex to WebORB, then you won’t be able to include ArrayCollections (or any other class that has no definition in Ruby/Rails) in the VO. In this situation, you could just take the array returned by the ActiveRecord association and store it in an Array in your VO, and then stick that array in an ArrayCollection on your ModelLocator for databinding.
Alternatively, if you want to store the ArrayCollection in your VO, you could just send updates using untyped objects. One reason to consider this approach is that if your storing a collection inside a VO, when you send that VO from Flex back to Rails you are sending all of objects in that colllection with it, which probaly isn’t necessary. Using an untyped object you can send just the information that you need to see, which means your over the wire messages will be much smaller.
March 16th, 2007 at 2:31 am
Got it! Thanks for the quick reply.
March 16th, 2007 at 3:50 pm
Derek,
I went with your first option and removed all ArrayCollections from my VOs. As a result, weborb no longer borks on the incoming VOs – Yay!
But now there’s another problem. I have a method in my weborb service which takes a single ContactVO argument like this:
def updateStudentContact(contact)
contact.save
contact
end
The ContactVO contains 3 arrays of VOs: phone_numbers, addresses, and email_addresses. I’ve inspected the object itself within the Flex debugger and it’s all nicely typed right down through the 3 VO arrays.
So far so good – but – when I call updateStudentContact, Weborb spoodles out these little INFO messages in my Webrick window:
“/weborb INFO: unable to load source file, PhoneNumber, hopefully Rails has already loaded it.
/weborb INFO: unable to load source file, RelationshipType, hopefully Rails has already loaded it.”
And my service capture tool apprehends this message when the service call faults:
“ActiveRecord::AssociationTypeMismatch
in WeborbController#index
PhoneNumber expected, got PhoneNumber”
I’ve restarted webrick many times and actually forced updateStudentContact to work by using a rails breakpoint call and then manually doing contact.save on the irb command line.
I also tried adding “include ‘Reloadable’” into my service class. That didn’t solve it either. I must be missing something obvious. Yikes!
Oh Jedi Master – you’re my only hope…
- TC
March 16th, 2007 at 4:38 pm
Just a follow up note. I can consistently get updateStudentContact to work the *first* time it’s called. After that, it’s all errors.
Thanks
March 17th, 2007 at 6:57 pm
OK,
I think I’ve figured it out. Based on this post:
http://www.themidnightcoders.com/forum/default.aspx?g=posts&t=118
I changed my classmapping source elements to the actual name of the rails model. So, instead of my classmapping looking like this:
com.nextk12.vo.PhoneNumber
PhoneNumber
PhoneNumber
It should be this:
com.nextk12.vo.PhoneNumber
PhoneNumber
phone_number
Because my rails model is phone_number.rb
This may have been obvious to everyone else, but it took me a while to get this.
Yipee!
March 19th, 2007 at 11:46 pm
An association-related possible WebORB issue here?
http://www.themidnightcoders.com/forum/default.aspx?g=posts&t=169
April 10th, 2007 at 4:18 am
I am confused as to how the has_many is registered. Where does the project_id get sent to the issue? It is making me a bit crazy. Am I right in assuming the IssuesVO passes this along?
If you had a join table to keep track of has_and_belongs_to_many, what would be the proper way to pass that information? Like if multiple users are assigned to multiple issues. What would I need to add on the Flex side and the Rails side to make this sort of association?
April 11th, 2007 at 9:27 pm
The Issue model has project_id attribute that stores the id of the project that the issue belongs to. You can look in the db/migrate folder to see all of the attributes for each model. The associations are all on the Rails side. Flex just gets the objects from Rails with whatever you put in them, it does not have anything to do with creating the association.
For many to many relationships I tend to prefer join models over join tables. You can read why here:
http://blog.hasmanythrough.com/2006/04/20/many-to-many-dance-off
Derek
April 12th, 2007 at 1:05 am
Even with a model using :through you have a join table between them, don’t you? I looked into that, but decided to stick with the methods in Agile Web Development – which doesn’t cover the join model. It makes better sense though.
Here’s my question I suppose, do you pass an object for the join table alongside your VOs?
Thanks for the assist Derek. These tutorials are great and it would have taken me weeks to get as far as I have with Cairngorm and Rails otherwise.
Cheers,
Joel
April 13th, 2007 at 8:01 pm
If you don’t send a object (like aArrayCollection) to Ruby you can use the meta [Transient] in your flex.
[Transient]
public var entryLinks:ArrayCollection;
April 13th, 2007 at 8:18 pm
#Question,
#How can i save a complex Object with complex Object
#from Flex to Rails to Mysql.
public class Gallery
{
public var id : int;
public var title: String;
[ArrayElementType("com.timeline.model.Image")]
public var arrImage: ArrayCollection;
}
#In rails, I have 2 Active records:
class Image
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.15.2/lib/active_record/base.rb:1858:in `method_missing’
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.15.2/lib/active_record/base.rb:1673:in `send’
…
April 14th, 2007 at 2:10 am
@David – thanks for the tip about the [transient] metadata tag.
How are you sending the Gallery class from Flex to Rails?
You will need to convert the ArrayCollection to an Array before sending it across the wire. You will then need to take that Array and save each of the Image models.
Derek
April 14th, 2007 at 4:05 am
[...] just learned about this tag today from a comment by one the readers of this blog (thanks [...]
April 14th, 2007 at 8:32 pm
Derek,
Yes i’m sending Gallery class from Flex to Rails.
And i think a can directly send ArrayCollection to Rails. Edit weborb-config.xml
flex.messaging.io.ArrayCollection
ObjectProxy weborb.v3types.ObjectProxy
April 17th, 2007 at 9:53 pm
@Joel – If you use a join model you do not need a separate join table, remember that a model is a wrapper around a table, so a join model is a join table, but with all of the benefits of using a model.
Your VOs do not need to know about the join table. The join is just there to create the association and acts as gateway between the two models. So if a User model contains:
has_and_belongs_to_many :issues
You would access the issues that belong to particular user like so,
@user = User.find(:first)
@issues = @user.issues
If you were to stuff this code in a service class, it would return the issues for the first user in your database.
April 18th, 2007 at 6:35 pm
@Derek – I appreciate your time and effort in explaining this to me. The model makes sense. How does the model know which issue belongs to which user?
In my case I am making a book library and sharing application. A user (UserVO) enters a book (BookVO). I have corresponding tables for each. Of course, lots of users might own a single book, so I don’t want multiple entries for twins. Initially I have put a User_ID field in each BookVO, but this locks the book to the user that first input the book. So without a join table in the middle keeping track of these relationships, I just can’t wrap my brain around it.
April 19th, 2007 at 4:48 am
Hi Joel,
The model (ActiveRecord) knows which issue belongs to which user because that is the info that is stored in the join table.
So if you have,
class Book < ActiveRecord::Base
has_and_belongs_to_many :users
end
and
class User < ActiveRecord::Base
has_and_belongs_to_many :books
end
then following the Rails convention for join tables (i.e., classes1_classes2) you will have a table in your database called,
books_users
books_users has two columns,
book_id
user_id
Ok, so now if you do the following,
@user = User.find(:first)
@books = @user.books
when you call @user.books Rails figures out a whole lot of things based on convention. First it checks the id of User model instance that was returned by User.find(:first). Then it looks for a table called books_users and finds all of the ones where the user_id value matches the id of the current user. Then it grabs the the value stored in book_id for each of these. Lastly, it searches through the books table for books whose id are in the list of book_ids and returns these as Book model instances to @books. See all of the hard work that ActiveRecord is doing for you?
Derek
April 19th, 2007 at 3:06 pm
If both of my VOs represent database tables, what fills in the values of the Books_Users table on the Rails side? Would there be a bit of code in the addUser service method, for example?
Cheers,
Joel
April 27th, 2007 at 5:27 pm
Please Help!!!
I am having trouble with the has_and_belongs_to_many association with WebOrb.
*** The Actors ***
Sql Tables
———-
table people
id: int auto-increment pk
name: varchar
table groups
id: int auto-increment pk
name: varchar
table groups_people
group_id: int pk
person_id: int pk
Ruby Model Classes
——————
class Person
April 28th, 2007 at 4:59 am
Hi Michael,
I think that maybe your post got cut off. Either try to re-post or just send me an email at dwischus [at] flexonrails [dot] net.
Derek