Ruby on Rails and Flex using rubyamf association errors

I’ll have to re-duplicate the exact error message on ruby’s side. From what I recall, this was obscured by a bunch of weird error messages that were deep in the codebase for rubyamf.

Basically, if your rails server barfs a bunch of errors when you try and load activerecord objects from an amf request, one cause of this can be the fact that you have associations setup in your rubyamf_config.rb file, and there are bad or missing foreign keys in the database for linking associated tables.

In the following example ruby barks when an account is loaded. Account has a location_id in the database to a location. If the location record with that id does not exist, ruby does not throw a nice error.


ClassMappings.register(:actionscript => 'Account', :ruby => 'Account', :type => 'active_record',
    :attributes => ["id", "location_id", "verified", "org_id", "login", "password", "email",  "name_title", "name_first","name_middle",
        "name_last","name_suffix","phone","phone_2","phone_3","last_login_at", "created_at", "updated_at", "business", "residential"],  
    <span style="color:#CC6666">:associations => ["locations"]</span>)

Events with non-DisplayObjects in the Mate Flex framework

So I was loving the MVC framework Mate, but started to run into issues trying to figure out best-practices for dispatching and handling events.

Researching:

1) How you dispatch events from non-view parts of your Flex Mate app

2) Is this a good practice and what is the best practice for using events in Mate with regards to loading an app’s data from a remote source and handling server data?

Results:

1) In a non-DisplayObject, don’t just use dispatchevent(), but you need to instantiate a Mate dispatcher.

At the top make sure you import the class.

import com.asfusion.mate.events.Dispatcher;

Then:

var myDispatcher:Dispatcher = new Dispatcher();
var qlEvt:QuotesLoadedEvent = new QuotesLoadedEvent(QuotesLoadedEvent.QUOTES_LOADED, true);
myDispatcher.dispatchEvent(qlEvt);

This worked for me. I was dispatching the event from a QuoteManager that was responding to the result of a RemoteObject call. But it seems that the listening component (a Box with a datagrid) would only hear the event when I did the following in an injector tag (target=”{QuoteGrid}”) in the eventMap:

<ListenerInjector method="resetQuotes" eventType="{QuotesLoadedEvent.QUOTES_LOADED}"/>

If I used:

<EventHandlers type="{QuotesLoadedEvent.QUOTES_LOADED}">
<MethodInvoker generator="{QuoteGrid}" method="resetQuotes"/>
</EventHandlers>

The QuoteGrid component did not hear the event.

2)TBD

See: http://mate.asfusion.com/page/documentation/tags/dispatcher

The main issue was dealing with events that were being launched from a Manager class, which was handling a remote response from php. After the response, in the manager, I was firing a custom Event that signaled the initial data had been loaded for the app, and then trying to listen for this data_loaded event to signal to the view to update the display (wasn’t a simple property injection since the display had filters, etc. which was making the data layer far more complex with a filteredArray, etc.).

This post: http://mate.asfusion.com/forums/topic.php?id=317 was helpful, when I realized why the hell my eventmap was not able to assign a responsive listener for the data_loaded event. The event was being fired from a Manager class, but nothing was listening or responding and I guess that is because the event map doesn’t handle events dispatched from non-DisplayObjects (like my QuoteManager).

So what is the best practice for notifying views that data has been loaded, when I cannot relying on simple property injection to get the data from the Manager to the view? TBD. Also, is injecting a listener int the eventMap the same as handling an event and invoking a method in the eventMap?

I want to 1) get a bunch of stock quotes for a dataGrid 2)After the data has been received, send it to the view, and not just update a property on the view but copy the data into various other properties so I can manipulate the data on the view with several filters and preserve the original state of the master ArrayCollection. I wonder if using expanded getters/setters on the original/master stock ArrayCollection and its source will be necessary. I would love to see some clear documentation on manipulating/filtering ArrayCollections and what happens to the Array source when the filter function is set.

I would also like to figure out a best-practice for handling server data, and responding to this data using the model concept of MVC and events in Mate. The documentation so far has been good, but not clear on how to accomplish the aforementioned goal.

Cruise Control and/or ANT out of memory error

When setting up a flex app auto build task, I started getting the following error consistently.

Error: null
java.lang.OutOfMemoryError

THE FIX, for me was: Add to ant.bat, antRun.bat

set ANT_OPTS=-Xmx512m
set ANT_OPTS=-Xms64m -Xmx512m

First I tried changing the Cruise Control memory settings in cruisecontrol.bat (CC_OPTS=-Xms256m -Xmx768m -Xmn256m).But I think it was less likely for the cruise control process to have memory issues than the ant tasks I was using (as Jeffrey pointed out before I could clean this up a bit – thanks).

I was noticing that the java.exe service that was handling the process would go up to 100 MB of memory usage, and then stop there, and then tank. The following article points out how to change the ant task memory settings. Because of the way cruise control was calling the ant task, it made it necessary to modify the the .bat files in the ant folder (You can use the <ant><jvmarg>… tag, as per the links below, in some cases). Once the .bat’s had the ANT_OPTS memory settings in place, the process would use more memory and build the flex app. Nice.

Check out the following articles:

http://confluence.public.thoughtworks.org/display/CC/OutOfMemoryError

http://cruisecontrol.sourceforge.net/main/configxml.html#ant

Flex Tree not allowing Drops

The Skinny

By using mx:Tree dropEnabled=”false” and registering the drag and drop listeners separately using the addEventListener Method with the use_capture parameter set to true, items could be consistently dropped from one control into the tree control. Otherwise, the drop was broken, not working many times, and the red ‘x’ disallowed drop feedback would persist, even when the drop should have worked.

I got it to work by changing
albumTree.addEventListener(DragEvent.DRAG_ENTER, onDragEnter, false, 0, true);
TO
albumTree.addEventListener(DragEvent.DRAG_ENTER, onDragEnter, true, 0, true);

Be sure and add DragManager.acceptDragDrop(UIComponent(event.currentTarget)); to the onDragEnter method (See links and discussion below).

Working with drag and drop in Flex Tree Controls

First – make sure you are following the adobe documentation, and the great advice found in the following article:

http://weblogs.macromedia.com/pent/archives/2006/11/tree_drag_and_d.html

On the adobe site, there is a great article about how to drop on to a tree control(Key here is dropEnabled has to be false on the tree, and you do your own drag and drop handling). This seemed to work better than the simpler example above where dropEnabled was true. I think relying on the default behaviors (dropEnabled=”true”) is kind of iffy, unless you are doing really simple stuff. Check the section ‘Dragging and Dropping to a tree control’ near the bottom:

http://www.adobe.com/devnet/flex/quickstart/working_with_tree/

The dropEnabled property of the tree component handles drag and drop in certain ways in which it makes it hard to override or use your own drag and drop event listening at the same time.

Also, if you have nested components and/or a more complex mxml interface, you may run into the following problem –

A flex tree nested in a few components was not accepting drops from a tileList nested in a few components. I think in traversing the components that the drag_enter precedence or firing was getting screwed up and not allowing drops. It would only accept drops sometimes. As you dragged over a VBox divider, the drop indicator (feedback) was showing a red x, and often, but not always, the red x would persist into the drop target the SHOULD have been allowing drops and drag enter. It was turning out that a slow drag would allow a drop, but a fast drag over to the drop target was not allowed, where the red x persisted.

Adding DragManager.acceptDragDrop(UIComponent(this)); where this is the parent container, just makes everything in the parent container accept a drop, which is not what I was looking to do. And it’s kludgey.

I got it to work changing albumTree.addEventListener(DragEvent.DRAG_ENTER, onDragEnter, false, 0, true); TO albumTree.addEventListener(DragEvent.DRAG_ENTER, onDragEnter, true, 0, true);

For some reason the use_capture parameter fixed this. The key (which I don’t posses yet) is in understanding the different phases of event processing. Capture, target, and bubble.

Adobe – “The use_capture parameter of the addEventListener() method lets you control the phase in the event flow in which your listener will be active. It sets the value of the useCapture property of the Event object. If useCapture is set to true, your listener is active during the capturing phase of the event flow. If useCapture is set to false, your listener is active during the targeting and bubbling phases of the event flow but not during the capturing phase. The default value is determined by the type of event, but is false in most cases.

To listen for an event during all phases of the event flow, you must call addEventListener() twice, once with the use_capture parameter set to true, and again with use_capture set to false. This argument is optional. For more information, see Capturing phase.”

Note – Changing the event priority higher didn’t work (albumTree.addEventListener(DragEvent.DRAG_ENTER, onDragExit, false, 10, true);)

Flex Builder – Please specify a context-root compiler argument.

I don’t remember ever having to do this, but all of a sudden I needed to:

add ‘-context-root /’ to the Properties->flex compiler ->additional compiler arguments

The error was:

The services configuration includes a channel-definition ‘java-secure-http’ that has an endpoint with a context.root token but a context root has not been defined. Please specify a context-root compiler argument.

Flex error 1105: Target of assignment must be a reference value.

From Adobe “You can assign a value to a variable, but you cannot assign a value to another value”. For me this happened when the ObjectProxy was not editable, but the object property on it was.

What does this mean? What is the difference between a value and a variable?

So it is pretty intuitive that a variable is a dynamic property that can change. But a value – what is that? Apparently a value is something that CANNOT CHANGE. So a read-only property, or something. So this error happens when you try and say something equivalent to 2=3. Make sure the thing on the left side of your assignment is allowed to change.

See http://curtismorley.com/2008/02/15/flex-2-flash-cs3-actionscript-error-1105 for a good theoretical example. The problem is that this error is triggered in situations where it wouldn’t seem like things you are assigning values to are read-only or un-changeable. But I think the bottom line is, if you get an 1105 error, you can assume that the thing on the left side of your assignment DOESN’T allow you to change it.

For me this happened because I wrapped an object in an object proxy, and then tried to set the value of the object proxy to the CreditVO (a custom Value Object based on a Remote class), instead of setting the object contained in the ObjectProxy (a variable) to the CreditVO. So the ObjectProxy itself was not editable, but the object property on it was.

“1105 Target of assignment must be a reference value. Description – You can assign a value to a variable, but you cannot assign a value to another value.”


//Simplified
myObjectProxy = theCredit;
//Mine 
model.creditSearchResult.getItemAt(opener.creditSearchResultGrid.selectedIndex) = theCredit;

Should be:


//Simplified
myObjectProxy.<span style="color:red">object</span> = theCredit;
//Mine
model.creditSearchResult.getItemAt(opener.creditSearchResultGrid.selectedIndex).<span style="color:red">object</span>= theCredit;

Line break in Flex or Actionscript 3 text

Displaying a newline in a UI component in flex was a bit tricky.

The following would not work:

somevar:String = “Here is line 1 text \n followed by line 2 text”;

 

The following worked in my situation.

somevar:String = ‘Here is line 1 text’ + ‘\n’ + ‘followed by line 2 text’;

If all else fails you can use a more explicit directive, i.e. use {‘\n’} intead of \n

http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=2&postId=9223

Receiving Flex Objects in Coldfusion, coldfusion component argument types

Flex Remoting with Coldfusion. Coldfusion Services and custom objects/components

I was getting frustrated when I COULD NOT receive a flex object as anything when a coldfusion service was receiving a remote call from flex. The coldfusion component had a method I was sending a call to. This method expected a struct arguement and then I was trying the argument type as on object. When I passed in the flex object to the remote method call in flex, when coldfusion received the argument it was breaking it apart and treating it as a messed up argument collection. Turns out you have to wrap a flex object in another object for coldfusion to receive it as a struct. Why the lack of documentation on this? I think flex remoting is really cool, but maybe it is a newer wave of development that just hasn’t been very popularized yet. I think that is changing.

In any case the following links really help with understanding how coldfusion and flex work together with remoting. Coldfusion components, like custom TO objects, can also be used across the wire, and vice-versa with flex objects. It is pretty slick, but you have to learn how to make coldfusion components and corresponding flex objects with properties that match, etc.

Nice article by Joel.

http://www.joelconnett.com/flexobjectstocoldfusion.html

I had originally found the following, which was helpful:

http://codingmurloc.wordpress.com/2007/05/15/passing-object-to-a-cfc-flex-or-cf-bug/

For custom component types, see also:

http://www.brucephillips.name/blog/index.cfm/2006/10/26/Exchaning-User-Defined-Objects-Between-ColdFusion-and-Flex

http://www.forta.com/blog/index.cfm/2006/2/1/The-Keys-To-Getting-CFC-ActionScript-AutoConversions-To-Work