Making RubyAMF more ‘Railsy’
Posted by Cliff
Note: read the notes at the end of this article first!
Ok, so we’re using RubyAMF trunk on a brand spanking new project, and all in all it’s pretty darn cool. I love AMF anwyay, irrespective of the crimes against standards, it’s efficient - and I like efficient. But I do care about standards, and for that reason I can’t bear the thought of producing a service that can only talk AMF, but I don’t want to go through extra hoops to achieve it.That’s one of the nice things about Edge (Oops, just remembered it’s now a release) Rails. Using respond_to, a controller can dynamically serve content based on the client. Meaning this is possible:
def ProjectsController
def create
@project = Project.create_with_company!(
params[:project],
params[:company]
)
respond_to do |format|
format.xml do { render :xml => @project.to_xml }
format.html do { render :action => “some_action” }
# etc..
end
rescue
# Blah blah
end
end
This is nice. It means that the only time we need to care about what the client is, is when we need to send something back. As long as we receive a standard params hash.I may well be wrong, but there doesn’t appear to be a way to configure RubyAMF to map an incoming Value Object straight to a hash. Instead RubyAMF wants to instantiate the appropriate ActiveRecord model for you, which means that the controller will ultimately need to behave differently when an AMF client makes a request. This is no good.So, after much experimentation with ParameterMappings, ValueObjects mappings and RubyAMF configuration settings, I came up with this little gem (why are these things never obvious until you’ve been around the houses a few times?). To map your incoming Value Objects directly to the params hash, declare your ParameterMappings like this example:
ParameterMappings.register(
:controller => :ProjectsController,
:action => :create,
:params => {
:company => "[0].attributes”,
:project => “[1].attributes”
}
)
Notice the call to .attributes. Now this controller will receive a hash containing two other hashes, one containing the company attributes and the other containing the project attributes; in other words, a regular params hash. Our controller can now simply return the results as AMF the same as any other request:
def ProjectsController
def create
@project = Project.create_with_company!(
params[:project],
params[:company]
)
respond_to do |format|
format.xml do { render :xml => @project.to_xml }
format.html do { render :action => “some_action” }
format.amf do { render :amf => @project }
# etc..
end
rescue
# Blah blah
end
end
It’s a bit of a hack. RubyAMF spends pointless time and effort gift wrapping an ActiveRecord model for us and we tear it to shreds and throw it away. But hey, it works, and us kids still get our toys.
Update: It appears I may have been hasty in my assumptions. Setting ParameterMappings.scaffolding to true will achieve the same effect. I know I’ve tried this, and I had an issue with it, I just don’t remember what it was. In fact I think I’ve possibly tried every single possible permutation of configuration settings..
Update: Indeed ParameterMappings.scaffolding does achieve the same effect, so this whole article is actually redundant. Ho hum :-)





