Unspace

Home
Work
Projects

Discover
On the Road
Contact
Ruby on Rails

Open Says Me

Bio_pete
:: Development
April 26, 2006 - over 2 years ago


Platform: Ruby on Rails 1.1.2
Tested Browsers: Firefox 1.5, IE 6.0, Safari 1.3.1
Tag As: Ajax, browser detection, Rails, before_filter, JavaScript, cookies
Editor: Stephanie Lyons
Illustration: Anthony Watts
Technical Review: , Dan Grigsby
Source Code: here - version 1.00
Demo Page: Open Says Me

As web developers, we have a serious issue to contend with: completely all-over-the-place support for Ajax. Prototype does a great job of abstracting the various browsers, but there are several pitfalls coming our way. XMLHttpRef is implemented as an ActiveX control inside IE, and that means that if a user has IE set to High Security mode, it's not going to work - even though it's an internal component! Further, the new changes Microsoft is being forced to implement as a result of a lawsuit ruling would see IE users having to click a response each time ActiveX is used in the browser. It's unclear how this might impact how we use Ajax in our web applications.

The good news is that we don't have to draw a line in the sand. We don't have to interrupt navigation with warnings about internet settings. We will not point at our potential clients and suggest that without JavaScript and cookies enabled, they will not be able to access the full functionality of our site. With proper planning, we can refactor our site architecture so that people with feature-limited browsers can use a site, albeit with some limits to functionality, but without being presented with an 'Upgrade or Else!' style ultimatum. The solution is remarkably simple.

Before Rails, every developer had their own slightly different code library which attempted to figure out which browser was running what version, whether Flash and cookies were enabled, and so on. Every time a new browser version came out, many of these scripts stopped working the way you expected them to. As these scripts were running in the client, when JavaScript was disabled you were often out of luck.

We will use all of these factors to our advantage. Browser war? It's payback time!

For this solution to work, we assume that a browser which supports JavaScript, cookies, and Ajax is capable of providing the rich scripting experience that we need. We can then work backwards from the best-case scenario to trick the browser into proving that it is capable of doing everything we need. We have structured our application so that modules which require advanced functionality are separated into their own controllers, while the majority of your site - your basic, primary functionality - is in controllers that everyone should be able to interact with, regardless of their browser configuration.

Discover_opensaysme_diagram

  1. In the application controller, set up a before_filter which checks for the existence of a cookie; I call mine 'okgo'. If the cookie is not present, it sets a variable that is picked up by the application layout view.
  2. If that value is true, a helper function renders a small piece of JavaScript which attempts to execute as the page loads.
  3. If JavaScript is enabled, an Ajax.Request calls a server action called 'write_cookie', which is declared in the application controller.
  4. If Ajax is enabled, 'write_cookie' uses Rails' RJS to instruct the browser to write a cookie - if cookies are enabled. This cookie is called 'okgo', of course.
  5. Inside your advanced functionality controllers, set a before_filter to check for the 'okgo' cookie. When someone running WebTV comes along and wants to see your fancy Live Datagrid, the before_filter quickly puts the kibosh on that action, and redirects them back to a static login page on your basic home controller. This will pick up people who are attempting to access resources that require authentication, as well.

In other words, if they don't have JavaScript, cookies, and Ajax - no dice!

When a user is redirected to the login page, you can formally request that they enter their login details or create a new account. Below this you should give a simple explanation of what browser functionality will be required to move further.

Open Says Me Example

The 'okgo' cookie is written to the browser, as seen with FireBug plugin in Firefox.

If you're developing Ajax applications, we can't recommend FireBug enough. It allows you to see every Ajax request that gets made, as well as the server response. It makes debugging stateless, asynchronous applications a breeze.

The Grass is Looking Pretty Darn Green Here

We have designed our application so that as much content and functionality as possible is accessible in controllers that do not have any requirements for session state, Ajax, or scripting functionality. This means that you really don't need that fancy Ajax login widget after all!

This solution has the potential to be fooled by someone that creates their own cookie. Yet what are they going to accomplish? If you perform server side validations, the worst case scenario is that someone could see your page in a static, non-functioning state. Just make sure that in your zealousness you don't ever assume that a browser reporting an 'okgo' cookie is an authenticated user.

We have a responsibility to be liberal in what we accept, and conservative in what we send. To me this means that the onus is on architects to make decisions early on which won't have a negative impact for users later. Designers aren't off the hook, and should be using standards compliant CSS for their layouts and styling. You refactor your site to work with what your user has. Make sure that a site is still useful even in a text browser! This attitude will make the web a better place for everyone.