Dec 18, 2009

Sneaky JSONP to do cross domain scripting

Last year I was working on a project which included an existing legacy web application communicating with an embedded iframe widget in it. Since we didn't want to go back to servers for calls; we *desperately* wanted to do cross site scripting between those two sites. Unfortunately; widget and host application were hosted separately and Javascript wouldn't work seamlessly due to cross domain security issues.
At that point the best I could do was a "hash fragment modifier" approach, which somehow did the trick and then using that token web servers synced up later between themselves. The whole solution worked quite well; and went into production and is running stably till today (hopefully).
But I had always wished there was a better way to communicate between those two. Now I am involved in developing public APIs for an e-commerce/social-networking site and I just stumbled upon JSONP. It's amusing how things just don't turn up with repeated Google searches but sneak in quietly; when you are searching for an unrelated problem.I wish I was wiser when I had to actually implement that solution. I spent several hours today understanding how Cross Scripting with JSON works and turns out it's such a neat way to do some things. Just wanted to share it with anyone; who may be hunting for a similar solution. There are two parts to the solution. One with JQuery (I gotta admit; I am just growing more and more fond of jquery; as it's absolutely brilliant) and one in simple HTML/Javascript language. I'll go with latter first.
  • Rule of thumb: If you make a ajax call to get data from a domain which is not in same domain as the hosted application and nor is a sub domain; then Java-script raises security errors and doesn't let you communicate. This is due to cross domain scripting issues. 
  • The Loophole: If you include a script tag for javascript on your page with src pointing to a javascript resource lying on a remote server it allows you to access and run that javascript. 
Using the second point what we do is; create script tag dynamically and assign it's source to a URL that returns data encapsulated in a method call. The condition is that method should exist in your web-page. This is JSON Data wrapped in a callback function. The limitation is that, both requesting domain and serving domain should know the name of the callback function. (That is if you are doing the plain HTML/Javascript way). Jquery provides seamless support for this in it's getJSON method. I am using twitter API's to fetch my Twitter stream; as twitter has a support for JSONP and while requesting for JSON, you can pass the callback function name. For those who are unaware; if you are working on Ruby on Rails; it's gonna be a piece of cake supporting JSONP in your APIs as if you look at the to_json method's documentation; it has an in-built support for callback method wrapping; all you need to do is pass additional parameter :callback. As long as the value for that is set; it'll wrap it in a req. callback method. Convention is, if no method name is specified; the default method name is "callback". Hope it has helped.

Dec 12, 2009

Reject/Ignore/Stop Rails Active Record Callbacks Selectively

Faced a small issue today. I had a model in rails; where Model had :before_save filter set for the model. To make things more complex before_save had not one, but several invocations.

Unfortunately one of those invocations went about fetching a service instance from injected spring context. This really pissed off a database migration script; because it didn't have spring context.

So effectively I needed to ignore that particular before_save callback. After a bit of googling I found the solution.

If you want to skip all the callbacks on a particular model; use following statement:
MyModel.before_save.clear

or to skip a particular method invocation following statement can be used:
MyModel.before_save.reject! {|callback| callback.method == :method_name}

This would skip the call to particular method invocation. It's particularly helpful in
  1. Rake Tasks, where you may not want some of the filters/callbacks to run as they do in actual code.
  2. Database Migration scripts
There can be other reasons; why you may want them to be skipped. Whatever works for you man..