See the release notes or keep reading.
With RubyAMF 1.0 I’m bringing a Rails Remoting gateway into the mix. I know some people thought it was cool that RubyAMF was not a Rails hitch-hiker. I thought so too. But I think what I’ve done is a really good rails implementation, and it will only get better folks. And I’m still supporting the standalone application servers bundled with RubyAMF.
The RubyAMF standalone app server is usually faster than using it through Rails. And quite honestly, most of the time a Flex app doesn’t need Flex and HTML versions. So why use Rails? ActiveRecord through Rails is dead slow, using straight mysql is so much faster.
The Rails gateway is really just hooking into everything else I’ve done with RubyAMF and wasn’t a lot of work to get it into Rails. Keep reading for a breakdown of everything that this gateway brings to Rails.
Gateway and Services Path
The Gateway for RubyAMF is located here: http://localhost:3000/rubyamf/gateway. The gateway is just a controller with a “gateway” action. So technically you could put it in any controller as any action. There is a small amount of code in the action so I’d just leave this as the default.
The services path is app/controllers so RubyAMF maps requests to your controller. Intelligently though.
Sniffing a RubyAMF Remoting request
What if you call a method on a controller that doesn’t send a correct response for AMF? RubyAMF injects an instance variable in your class called “@is_amf”, which is set to true when the RubyAMF gateway is hit. This helps so you can place some logic in your controller methods to respond to AMF. Heres a quick example:
class MyTestController < ActionController::Base def test if @is_amf return User.find(1) else #do some more processing, etc end end
So that helps a lot. No more duplication of methods just to return AMF only content. And no more creating service classes just to house methods that already have functionality in your controller. Cool.
Remoting parameters map to params[] hash
Another feature is parameter hash mapping. From your remoting request, parameters get mapped into the params[] hash. So if you send 2 parameters, they get mapped to the params[0], params[1] hash.
The reason for this is that if I didn't map them into params, they would have to be declared in the method definition like so "def show(id)". But that will break Rails if say; you're viewing it through a browser or an XML REST there will be no parameters so it would break. You can shut this functionality off in the rubyamf_controller and have it be mapped into method parameters as well.
There isn't a way to supply symbols for hash keys. Like params[:id], because the parameters from remoting are just the values and no names associated with them.
Handle faults easily and effectively
Handling Model errors gracefully and sending back a useful error object to Flash is cake too. Here's an example:
require RUBYAMF_HELPERS + 'fault_object'
class MyTestController < ActionController::Base
def test
if @is_amf
@u = User.find(1)
if @u.update_attributes(:id => 45) == false
return FaultObject.new(1, 'Error updating ID')
end
end
end
end
This is a pretty simple example, but the point is that fault objects get mapped to your onFault handlers correctly in Flex or Flash. An object with the code, message, faultCode, and faultString properties are set.
Not only can you specifically return a FaultObject, but any exception that happens in rails will get sent back to Flash as a valid FaultObject. No more shots in the dark.
Why no REST with "render :amf => @ar.to_amf"?
I thought about doing this. There is one problem. HTTPRequest doesn't expect AMF data as a response. I started to write a wrapper for HTTPRequest to allow AMF as a response. And internally I would deserialize the AMF and provide that as a result.
But then I got thinking. Why the hell am I doing this? Flash Remoting is already implemented. Just because some kid wants to call localhost:3000/controller/show/4.amf because it looks cool doesn't mean it's the best implementation. In the case of Flash Remoting it's not a good option. Don't be a REST snob and assume it would be better.
So for now, @is_amf is how you sniff for a RubyAMF request. In the future I might implement a "render :amf => obj". But I think right now people would be confused in thinking it's REST, which it's not. So just exposing it like this at first and how to use it is key.
ActionController Filters
Most filter types are supported. Here is a list of supported ones:
-before_filter
-append_before_filter
-prepend_before_filter
-before_filter{|controller| ...}
-append_before_filter{ |controller| ...}
-prepend_before_filter{ |controller| ... }
-after_filter
-append_after_filter
-prepend_after_filter
-after_filter{ |controller| ... }
-append_after_filter{ |controller| ... }
-prepend_after_filter{ |controller| ... }
-skip_filter
-skip_after_filter
-skip_before_filter
After filters aren't enabled by default. You must call self.allow_after_filters in your action. That tells RubyAMF to execute all after filters. This was done because most of the time after filters won't be executed. If you do allow after filters, make sure to use @is_amf in one of the after filters and return a valid object to Flash.
A filter can be halted at any time by returning false. If it is halted, an exception is thrown to the player.
I don plan on implementing around filters and class filters. That will be in a another release soon.
Authentication
Yes, authentication is in place. On the client side you need to use either setCredentials or addHeader. In your controller action you can call amf_credentials(). That returns a hash with the username / password set in it ({'username' => 'whatever', 'password' => 'whatevet'})
It should be simple to use authentication plugins as well. You'd just have to update the plugin to use the new amf_credentials method as a way to get the username and password.
Sessions
Sessions should work fine with Rails. I currently don't have sessions in the standalone application server, but will possibly put them back in.
So now that RubyAMF is stable, and there are multiple ways of using it. There are a couple things left needing to be done.
1. One thing I need is some help testing RubyAMF Rails plugin as much as possible, finding what situations may break it, hearing if you like it and what could be changed, etc.
2. Screencasts, tutorials, blogging. (hopefully not just from me. Help!). PS. RubyAMF and myself are making our 2 chapter debut in an upcoming Flex book.
3. C extension. I've been putting this off, like way off. RubyAMF needs to be stable and production quality before even worrying about the C extension. It will happen though folks. And now that 1.0 is done, you can expect me to be a little more serious about it.
4. Build some apps with it. Did you know you can use rubyosa (An Applescript bridge for Ruby) to control apps on your mac? Check it out.
In case you didn't hear - RubyAMF is now under an MIT license. All Free. Stay tuned for whatever the hell else comes up. And get on the forums, or mailing list. I will be putting as much documentation as I can on the wiki but it might take me a couple days to get it all straightened out and the way I like it. So if there are questions, use one of the two.
- Aaron


