RubyAMF. Flash. And Rails’ Params

I’d like to shed a little more light on the best ways to send parameters to RubyAMF Rails, so that you can use params[:]. Specifically using Flash 9, NOT Flex. The most important two things to note are these:

  • Any objects properties whether it be a basic object, or value object get merged into the params hash. ONLY the first parameter gets merged though.
  • Any incoming value object also gets put into params[:classtype]. So if an incoming VO is of the type “vo.Event”, it will be put in params[:event]. This will enable you to fully use scaffolding without adding is_amf conditionals.

So what does this mean? If you send parameters correctly from Flash, there are only a few updates to get everything working correctly on the rails side. Here’s a generic example that should translate to a real working example.

RAILS:

class MyService < ActionController
  def update
    user = User.find(params[:id])
    if is_amf
      u = user.update_attributes(:name => params[:name], :email => params[:email])
    else
      user = User.find(:id)
    end
    if u
      render :amf => true
    end
  end

  def create
   if is_amf
     user = User.new({:name => params[:name], :email => params[:email]})
   else
     user = User.new(params[:user])
   end
   if user.save
     render :amf => true
   end
  end

  def destroy
   user = User.find(params[:id])
   user.destroy
   render :amf => true
  end
end

So in this example the destroy method works without having to mix in the is_amf variable. The create and update method has to mix in the is_amf variable because we’re not passing value objects back and forth.

Here is the corresponding AS3 to call these methods correctly.

AS3

function createUser():void
{
  myservice.create([{name:'asdfasdf',email:'aaron'}], onResult,onFault);
}

function updateUser(user:Object):void
{
   //user should be  => {id:1, name:'Aaron', email:'aaron@something.com'}
   myservice.update([user],onResult,onFault);
}

function destroyUser(id:Number):void
{
  myservice.destroy([{id:id}],onResult,onFault);
}

So what do we do to update the create and update methods so they don’t have to use is_amf? Value objects or _explicitType. These are two options to help you map everything the way you want. Here’s how they both work.

Value objects are simple. They boil down to a generic object with one extra piece of information – the class type. In our case. A ‘User’ class. So when you instantiate a value object, and send it over to RubyAMF, all your properties come over in a generic object, but it also sends the class type. Pretty simple. On the RubyAMF side your class type is caught and a Value Object of the same type is instantiated in Ruby / Rails. So if your value object is a User class, it is in turned mapped to params[:user].

So do we absolutely need value objects to get the params[:user] hash to be the correct object? No. RubyAMF uses a special property to handle value objects on the server side. _explicitType. If you send a generic object with the _explicitType property, it will be turned into a corresponding value object for you. It just so happens that the _explicitType is used to map a value object class to params[:classtype]. So we can use this to map our generic object to the params[:user].

Let’s look at how we can update methods so we don’t need to use is_amf.

Rails:

def create
  user = User.new(params[:user])
  if user.save
    render :amf => user.as_single!
  end
end

def update
  user = User.find(params[:id])
  if user.update_attributes(params[:user])
    render :amf => true
  end
end

AS3

function createUser():void
{
  myservice.create([{_explicitType:'user', name:'Aaron', email:'aaron@something.com'}],onResult,onFault);
}
function updateUser(user):void
{
  //uyser should be => {id:1, _explicitType:'user', name:"Aaron", email:"myemail"}
  myservice.update([user],onResult,onFault)
}

So by specifying the _explicitType property, it’s going to put an active record update_hash in params[:user]. Pretty cool. Now I’m not suggesting you use _explicitType at all times as it’s kind of a hack. You should use value objects instead. But hey, you’ll probably benefit from knowing more about RubyAMF.

Please let me know if there are any questions or suggestions for making it better.

Gnana said,

September 18, 2007 @ 06:48

Great.
So, does this work under Flex? I had the doubt as you started off this blog post by stating “…Specifically using Flash 9, NOT Flex.”.

-gnana

aaron said,

September 18, 2007 @ 09:27

Yes, it will work in Flex as well. I was emphasizing Flash because usually in Flex – value objects are a default piece of the application. With Flash however, a lot of people won’t be using value objects. So this was a tip for those flashers who wanted to be using the params[:] correctly. -Aaron

Gnana said,

September 25, 2007 @ 06:08

_explicitType works like charm! However, the AS3 code example didn’t work.

service.create({‘_explicitType’:'project’, ‘name’:project.name});

I am passing just the {} object instead of [{}].

I’m using the rubyamf trunk.

-gnana

aaron said,

September 25, 2007 @ 08:39

Sorry Gnana, was just more of an example, not meant to be taken verbatim.

RSS feed for comments on this post · TrackBack URI

Leave a Comment