Jan 13
Part 4 – Flex Cairngorm/WebORB Issue Tracker Tutorial – Invoking ActiveRecord Methods Directly From Flex
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 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.

January 15th, 2007 at 12:31 am
2. Open up the remote-services.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:
Correction to file name:
remote-services.xml = remoting-config.xml
January 15th, 2007 at 12:40 am
Right you are. Thank you for spotting the error.
April 10th, 2007 at 1:24 am
This seems like a bad idea to open access to classes on the back end. What happens when the person decompiles the file and then writes something that calls service.find_by_username(username).delete() or some other function they shouldn’t. Maybe we can set up something to prevent these things on the server but it seems like this might open up big holes in security. If there is an answer I might convert tomorrow but this could be very bad.
June 9th, 2007 at 1:01 am
I think this is a great concept, but I have to agree with Tyler. You’d have to be very careful to only open some of the methods, and be amazingly restrictive about what you returned. Once you have access to an object, you can access almost anything related to that object. Imagine calling service.find_by_username_and_password(’valid_user’, ‘valid_password’).class.find(:all) to get a full list of users and passwords.
Additionally, even if you only expose certain methods (find_by_username_and_password), if the user is able to see your internal data structure, they might now know that your DB has a field “is_superuser” and knows better how to attack you via other methods.
I imagine WebORB has a lot of security options, but my problem would be forgetting to secure that one, seemingly-harmless method that turns out to give a hacker exactly what he needs to totally trash my app’s data.
January 13th, 2009 at 7:35 pm
I really like this project and I downloaded the code and looking thorough it . I cant seem to find the UserService in any of the code. Also it would be useful to have a SQL Script to create the db if thats available.
Thanks much again
Prem