You are here: Blogsphere Longtail
Keep up to date with your favourite Rails bloggers in context.
RESTful JSONP in Rails using Rack middleware
Rails 2.3 has finally included support for Rack. The Rack project (http://rack.rubyforge.org/) consists of an abstraction layer on top of the webserver that provides a common set of services for developers while hiding the complexity of the web server software whatever it should be (mongrel, glassfish, thin, etc).
The support for Rack is a major accomplishment of the Rail Core Team and opens a lot of interesting new capabilities for the framework users.
In this post entry I will comment a possible use of Rack to provide support for RESTful-like requests for JSONP in Rails.
As you surely know, current desktop browsers only give support for GET and POST HTTP requests. This is a serious difficulty for clients trying to follow REST design guidelines in browser clients, since PUT and DELETE methods are needed to carry request to the server asking for the update and deletion of a resource.
Rails address this problem allowing to pass a '_method' parameter in POST requests that overwrites with its value the POST method of the request. In this way, PUT and DELETE requests can be sent from a HTML form or from an AJAX request.
But this feature only solves half of the problem. Web browsers implement a security model known as the Same Origin Policy (http://en.wikipedia.org/wiki/Same_origin_policy), where only requests to the same domain of the current URL are allowed. This policy effectively forbids cross domain AJAX requests. At least until a common specification for cross domain XMLHTTPRequests can be agreeded and implemented (http://dev.w3.org/2006/webapi/XMLHttpRequest-2/).
One work-around for this problem has been found in the use of JSONP (http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/) a technique where a new SCRIPT tag is inserted into the web page DOM with a callback parameter. The server answers with a script where the callback parameter value is used as a function name that is invoked with the data from the server passed as the actual parameter invokation value.
JSONP, though nothing more than a hack, is been used by many web pages and services to provide data to javascript clients and mashups. A big problem with JSONP appears when you try to use JSONP in a RESTful way. Including the SCRIPT tag in the page initiates a new GET request to the server, so if you wants to use JSONP to send a request for creating a new resource (POST), updating it (PUT), or deleting it (DELETE), you must use some work-around like the use of the _method parameter in Rails. But the overwriting of the HTTP method in Rails only works with POST request: no RESTful JSONP for you my friend.
Of course, you can always try to modify the behaviour of the method override mechanism of Rails with a little bit of monkey patching. Solutions in these direction has been proposed (http://www.actsasflinn.com/2008/06/13/cross-domain-restful-json-p-with-rails) but they are very likely to break with each new Rails release.
With the support for Rack in Rails 2.3 the situation has changed and a cleaner way to change the behavior of MethodOverride in Rails can be built.
Now, MethodOverride is a class of the Rack Rails middleware stack (http://rack.rubyforge.org/doc/classes/Rack/MethodOverride.html). Rack Rails allow developers to insert new middleware classes in the stack (http://guides.rubyonrails.org/rails_on_rack.html), so you can easily add a new middleware before MethodOverride that allows the use of _method parameters with GET requests, without the need of monkey patching:
module SemanticResource
# Allows overwriting of HTTP method also in
# GET HTTP requests in order to allow
# RESTful JSONP calls
class RestfulJsonpMiddleware
HTTP_METHODS = %w(GET HEAD PUT POST DELETE OPTIONS)
METHOD_OVERRIDE_PARAM_KEY = "_method".freeze
HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE".freeze
attr_accessor :method_parameter_name
def initialize(app)
@app = app
@method_parameter_name = METHOD_OVERRIDE_PARAM_KEY
end
# We check if the method parameter is in the request
# and set up the request to allow the execution of the
# overwritten HTTP method
def call(env)
req = ActionController::Request.new(env)
method = req.params[@method_parameter_name]
method = method.to_s.upcase
if HTTP_METHODS.include?(method)
env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"]
env["REQUEST_METHOD"] = "POST"
env[HTTP_METHOD_OVERRIDE_HEADER] = method
end
@app.call(env)
end
end
end
And now we can add the middleware in config.rb
config.middleware.insert_before(Rack::MethodOverride,SemanticResource::RestfulJsonpMiddleware)
That's it, cross domain RESTful AJAX for Rails in a little bit cleaner way! You must take some time to consider the security implications of this change in your application though.
Watwet from karim [04/07/2009 16:01]
Watwet from ymj [04/07/2009 15:27]
RE: RE: RE: Папку в архив.. как?!
RE: RE: Разграничение прав доступа
RE: проблема при использования attachment_fu для аплоада
Watwet from triplem [04/07/2009 15:05]
Watwet from mudoveee [04/07/2009 14:40]
Ich find die Temperatur ja geil... Vor allem auf der Wiese am Rursee :)
Watwet from mudoveee [04/07/2009 14:10]
Watwet from mudoveee [04/07/2009 13:55]
Unlogisch
Около дюжины способов запуска под-процессов в руби
RE: проблема при использования attachment_fu для аплоада
RE: Разграничение прав доступа
Watwet from mudoveee [04/07/2009 12:15]
Watwet from triplem [04/07/2009 12:10]
Watwet from jarkas [04/07/2009 12:00]
RE: RE: RE: проблема при использования attachment_fu для аплоада
RE: Разграничение прав доступа
TemplateWire offers premium XHTML / CSS website templates, flash templates, logo templates at affordable prices. Created by professional designers, built with simplicity, versatility and ease of use in mind, our premium design products are available for immediate download.
RE: RE: Папку в архив.. как?!
RE: Папку в архив.. как?!
RE: RE: Папку в архив.. как?!
Vyplatí se refaktorizovat i starý kód?
Každý větší program má v sobě alespoň jeden kus kódu, na který se dlouhou dobu nesahalo, protože to prostě nebylo potřeba – funguje a dělá to, co má. Kvalita takového kódu je ale obvykle nižší než kvalita zbytku programu, protože se mu nedostalo dalšího vývoje a refaktorizací.
Joakim Karlsson si všiml zajímavé věci: pokud do takového kódu z nějakého důvodu po dlouhé době zasáhnete, je vysoká pravděpodobnost, že do něj brzy budete muset zasahovat znovu. Změny mají tendenci se kupit, při testování narazíte na chyby v původním kódu apod. Je to poněkud neintuitivní, ale i dle mé zkušenosti to tak opravdu je.
Co toto pozorování znamená pro praxi? Při zásazích do starého kódu je obvyklé provádět změny způsobem, který se co možná nejméně dotkne stávajícího kódu, a to i za cenu nižší kvality výsledku. Logika velí, že nemá smysl se snažit cokoliv měnit a vylepšovat, když se sem stejně nikdo zase dlouho dívat nebude. Joakimovo pozorování právě tuto logiku narušuje a indikuje, že i starý kód se může vyplatit začišťovat a refaktorizovat – zkrátka aktivně zlepšovat jeho kvalitu, stejně jako u kódu živého – protože ve skutečnosti není tak mrtvý, jak se zdá.
Joakim se snaží své pozorování dokládat na analýze Subversion repository Pythonu a GCC. Jeho metodika je ale velmi sporná – měří intervaly mezi změnami ve všech souborech, nijak neodlišuje starý kód. Dochází tím pádem neodvratně k histogramu s exponenciálním rozdělením, což by předpověděl každý absolvent kurzu pravděpodobnosti a statistiky.
Celý článek je tak třeba brát spíš jako anecdotal evidence a námět na zamyšlení a diskuzi. Vzhledem k tomu, že údržba starého kódu je reálný problém, by se ale myslím vyplatilo problém prozkoumat trochu hlouběji.
Tell us what you think of the new BlogSphere feature. We are continually looking to improve and update the
functionality based on your feedback.

Find your next Ruby on Rails project or job.
Exclusive content,
regularly updated - onsite and tele-working positions listed.
Pat is a hacker and his code is a pleasure to use.
-
B.C, United States