Wednesday, 21 June 2006
How to register a new MIME type in Rails
« eclipse 3.2 | Main | Strange interaction between Mozilla and WEBrick »It's almost summer and it's a lot better playing volleyball under the sun than writing about technical stuffs. Anyway I've a blog and I must feed it so I'll try to add a post every one/two months. Hence, this is for June and July :-) .
The REST web-service support in Rails 1.1 is nice and powerful but how to add a new MIME type management, specifically a text/json [1] one? I haven't found any documentation about this and so I dug into the source code searching for a solution. I ended up with the following (after not few troubles):
require 'json' # register a new Mime::Type Mime::JSON = Mime::Type.new 'text/json', :json Mime::LOOKUP[Mime::JSON.to_str] = Mime::JSON # its default handler in responder class ActionController::MimeResponds::Responder DEFAULT_BLOCKS[:json] = %q{ Proc.new do render(:action => "#{action_name}.rjson", :content_type => Mime::JSON, :layout => false) end } for mime_type in %w( json ) eval <<-EOT def #{mime_type}(&block) custom(Mime::#{mime_type.upcase}, &block) end EOT end end # its param parser ActionController::Base.param_parsers[Mime::JSON] = Proc.new do |data| {:resource => JSON.parse(data)} end
require 'json'
is for the json library by Florian Frank.
Note that inserting the new Mime::Type into the LOOKUP
Hash is fundamental because otherwise:
- one can't register the param parser using the constant but has to write
ActionController::Base.param_parsers[Mime::Type.lookup('text/json')] = ...
; -
a lot more subtle, registering the param parser with this last instruction create a completely new Mime::Type object
o
ando.hash == Mime::JSON
is false, consequently the responder isn't able to find a match!
In fact the class Mime::Type doesn't opportunely redefine the Object#hash method though it modifies Object#eql? in order to make trueo.eql? Mime::JSON
. I think that this isn't appropriated:[...] must have the property that a.eql?(b) implies a.hash == b.hash [...]
(from Ruby core RDoc documentation)
Now in controllers you can write something like:
respond_to do |wants| wants.json wants.xml wants.html end
Moreover, if your request has the right content type you'll find in param[:resource]
a Ruby Hash corresponding to your JSON object.
So far, so good but I wonder if there isn't a cleaner way to do this ...
[1] actually, the official MIME type for JSON is application/json but dojo recognizes text/json. Anyway my troubles with dojo are material for another post that maybe I'll write in August ;-) .
Technorati Tags: Ruby on Rails JSON web-service REST
Comments on this entry:
Just a question. Where do I add this code? I tried adding it to the controller, but the first time I run the controller, Rails throws a error.
I was thinking of putting it in environment.rb. Just wondering if there is a better place.
indeed I put it in environment.rb . For better order, you can require it from an external file (I believe)