RubyAMF 1.3 RC1

RubyAMF 1.3 is almost ready and includes many new features and improvements. Here is the first of two release candidates. I wanted to get this out because there are a lot of improvements and additions.



First let’s talk about what’s changing for both the Rails and Standalone version. And what’s include in RC1.

Name Changes
Up until now I’d been referring to RubyAMF as “standalone” and “on rails”, I’m going to start calling them “RubyAMF Lite” and “RubyAMF Rails”. Lite being the built in application server. RubyAMF Rails of coarse means running in Rails. For short I’ll be refering to them as “RAMFL” and “RAMFR.”

Bug Fixes
There were three critical bugs found in 1.2 that probably caused a lot of headache. And possible “screw it” scenarios. Two of these are fixed in RC1.

The most notable was the “nil.unpack in read_word8″ error. When using the flash debug player, about 50% of the time you would encounter that error. The other 50% it was fine. This was caused by Rails’ ActionPack / ActionController gem.

Rails’ ActionController has a line that fixes AJAX requests from Safari. Safari appends a \000 to the end of the binary stream, which Rails doesn’t like.

Here’s the exact line from actionpack1.13.3/lib/action_controller/cgi_ext/raw_post_data_fix.rb

# Fix for Safari Ajax postings that always append \000
content.chop! if content[-1] == 0

So ActionController chop’s that last byte off – IF the last byte in the stream is \000. BUT AMF also has an \000 as the last byte. So as mentioned, half of the time ActionController was chopping off the last byte, thus causing the RubyAMF deserializer to choke on it. I’ve put a bug fix in the deserializer to handle this case.

RubyAMF configuration file
I moved value object definitions and adapter definitions into a new configuration file.

RAMFR, the config file is in rails/config/rubyamf_config.rb.

RAMFL, the config file is in services/rubyamf_config.rb

Value Objects
1.3 brings completed value object functionality and ActiveRecord value objects. What does this mean? Now you can pass ActiveRecords back and forth with no further work on your part.

Here is an example value object definition from the config file:

ValueObjects.register({:incoming => 'Person', :map_to => 'Person', :o utgoing => 'Person' [, :type => 'active_record', :instance => 'universalremoting'] })

In any VO definition, :type, and :instance are optional. When you supply the :type of active_record, RAMFR knows to turn an incoming Person object into a Person active record. Perfect.

Also, in this example you notice the :instance property. This is a new feature for RAMFL and is never needed for RAMFR. Keep on reading. The section about Application Instances is what this applies to.

ActiveRecord#as_single!
If you want to return a new ActiveRecord, and don’t want it to be returned in an array (for a dataProvider), you use the new ActiveRecord::Base#as_single! method. This tells RubyAMF to write the result as an object, not an object in an array ({}, not [{}]). This is something that needs to be specified intentionally.

The reason why this needs to be called intentionally VS me catching a single in RubyAMF and sending it back as just the object is this – say you have a service that returns User.find(:all). What if you only have one record? If I sent it back as just the object, chances are your onResult would throw an exception because you were expecting an Array.

By making you intentionally call it, that must mean you know your onResult method is expecting an Object or VO. Sweet!

Here’s a quick example:

def newUser
  u = User.new
  u.name = 'dave'
  u.phone = '234234234'
  u.save
  return u.as_single!
end

This example returns a User value object back to your application. So you would access the name property like so:

function onResult(event:ResultEvent):void
{
   var u:User = event.result as User;
   trace(u.name);
}

If you don’t use “as_single!”, the result would be access like this:

function onResult(event:ResultEvent):void
{
  var u:User = event.result[0] as User;
  trace(u.name);
}

Recursive ActiveRecord Adapter
The ActiveRecord adapter is now recursive to include associated model data. Heres’s an example.

User.find(:all, :include => :addresses)

In the resulting array, each item in the array has an “addresses” property that is another array of either Objects or ActiveRecord value objects, depending on whether or not you’ve defined a VO mapping for Address.



Whew that was a lot! Everything I just went over is available in both RAMFL and RAMFR.

Now let’s talk about what’s new for Lite.

Application Instances
Application Instances define a scope that allows RubyAMF to initialize ActiveRecord and load models for a request. They also create a scope for value object definitions. If you have multiple applications running in RubyAMF Lite with the same model names, you can declare a value object to part of an application instance so that it will always use the right model.

For every request, RubyAMF Lite tries to match the target path (org.package.SomeService) against an Application Instance definition. If a matching definition is found for that request, ActiveRecord is initialized, models are loaded and the database is connected to; based on the parameters you specify in the definition.

Here’s an example app instance definition from a config file.

Application::Instance.register({
  :name => 'universalremoting',
  :initialize => 'active_record',
  :source => 'org.universalremoting.browser.*',
  :database_config => 'org/universalremoting/browser/test.yaml',
  :database_node => 'development',
  :models_path => 'org/universalremoting/browser/support/ar_models/*'
})

Application instance definitions are not required for RubyAMF Lite to function properly. App instances main purpose is for incoming ActiveRecord value objects. Because ActiveRecord must be connected before instantiating an AR instance – app instances allow RubyAMF to catch requests and do the necessary AR connecting before you receive anything in your service method. So if you’re expecting ActiveRecord value objects you MUST define an application instance.

These definitions also make your service “model” enabled. By that I mean you don’t have to require rubygems, or any of your model files. You can just use them. Because they’re loaded when the application instance is initialized.

If you’re not using ActiveRecord value objects, no application instances are necessary, and RubyAMF Lite will function as normal.




Other Changes

Rails Installer
The Rails installer now puts a rubyamf_config.rb file in rails/config. This is where ValueObjects, and Adapters are defined.

The Rails installer now has 1.3RC1 in it.

ruby script/plugin install svn://rubyforge.org/var/svn/rubyamf/tags/current/rubyamf




So what’s next?

1.3 RC2 is next. In 1.3 RC2. I will fix the last outstanding major issue (bug number three of the three major bugs in 1.2). This issue is with RubyAMF Rails specifically. It was not Production environment friendly. No excuses – I put the Rails plugin together pretty quickly and a I made a slight oversight in the design. Yay! Anyway, it will be fixed an RubyAMF will be fine in production environment.

The bug is that I re-define the ‘render’ method of ActionController::Base. In development environment this is fine. But in Production mode, the Rails framework is not re-loaded for every request, thus once a single RubyAMF request was made, you no longer have render :[format]. Except of course :amf. But that’s probably not going to work for everything.

After RC2, the official 1.3 Final will be released. After that who knows. RubyAMF is scheduled to be in one book for sure. Plus I’ve dabbled in a Ruby FMS RTMP implementation. And I still need to write that damn C extension. I’m really looking forward to the future of RubyAMF. It can only get better.

Also, I’m moving to San Francisco. I’d like to start some RubyAMF sessions so I can meet people who are trying RubyAMF, and answer questions for anyone.

Also, for those who may have remembered talks of the Universal Remoting Group, I’m also sitting on a Universal Remoting Service Browser that enables custom AMF Format de/serialization tests so that any remoting implementation can automate AMF de/serialization correctness. Code generation, service browser, result inspection, recordset rendering, call histories, authentication, retry’s, etc etc. Stick around for that.

Also, please be patient while I update the entire wiki for 1.3. Just email me if anyone has any questions.

-Aaron

Jose said,

August 28, 2007 @ 00:14

Very exciting stuff Aaron. Was the Datetime bug fixed too? I’m currently using WebOrb for work because of some of the bugs you just fixed, but I’m reading to jump on RubyAMF once all this is fixed.

aaron said,

August 28, 2007 @ 08:43

Yep that was fixed. -A

Alastair said,

August 31, 2007 @ 07:44

Hey Aaron,

These updates are great, I have to put my hand up as having a “screw it” moment but weborb’s relative slowness will have me running back to rubyamf once it’s ready.

I’m not sure if this is covered in the bug fixes but when you run a Flex app in debug mode you get Rails argument errors (0 for 1).

The new SSR is awesome too, using it in a PureMVC project and nothing could be simpler :)

Welcome to the west coast!

aaron said,

August 31, 2007 @ 19:37

Hey Alistair, Thanks for the SSR complement, it does indeed make remoting cake! Just be careful when using AMFPHP/Flash9/SSR. Check out this post:
http://blog.rubyamf.org/?p=22

RSS feed for comments on this post · TrackBack URI

Leave a Comment