Monday, March 28, 2005

AJAX and Rails demo application: taskTHIS!

I thought that since I was involved with the new AJAX stuff in the latest Rails (0.11.1 as of this writing), that I would create a quick demo application showing how to actually use the stuff.

So I present to you taskthis!

Before you roll your eyes and say: “Ugh! Another todo list example?!”, this one is different! Honestly. Sort of. It's using the new Rails (0.11.1) asynchronous AJAX tools. It's using them a lot. Plus, you can download the source and play around with it.

It's been tested on Safari and Mozilla blends (Firefox/Camino), but not too extensively on Windows/IE. So I'd appreciate a shout out if you find any issues there.

Links

Sunday, March 27, 2005

Rails 0.11.1

The new gem of Rails with the AJAX enhancements and lot of other stuff is out! Get it while it's hot!

Saturday, March 26, 2005

Woo Hoo!

rails_logo_remix_small.gifI'm officially a Ruby on Rails contributor! Very cool.

Well, I thought I'd post an update. My changes were approved and merged into Rails' SVN. So, if you are using the latest-greatest code, then you can add a :position symbol to form_remote_tag or link_to_remote with one of the following string values: before, top, bottom, after, replace (default).

For my next idea... I was thinking of making the AJAX.Updater a little smarter by having it check the type of element it's updating. It should be able to set the value of a form field, if it's the update target.

But that leads to some interesting questions. How do we handle different types of input elements? text and textarea are easy -- just set the value. What about checkboxes, radiobuttons, and listboxes? It seems like you would be changing the selectable values for radiobuttons and selectboxes... And I have no idea what would change on a checkbox. You could change the value, but why? You could have it selected or not, but why would you need AJAX for this?

Why is covered, now for the How

Actually, let's talk about the Where. I've been talking about positionally adding content to DIV's, throwing around symbols like: before_begin, after_begin, before_end, and after_end. But what do they mean? Where is the content going using these different update methods?

I'm glad you asked -- saved me the trouble. It will position the new content relative to the target element. Specifically, in Rails, the element with the id you give as the :update param to form_remote_tag. Example:

<%= form_remote_tag( :url => url_for( :action=>'ajax_method'),
) %>

In this case, the :update_method is relative to an element with the id of 'my-target-div'. OK, so we know where the after_begin method is relative to, where exactly will it put it? Another good question!

insertAdjacentHTML.png

So, the target element is the big gray box in the middle. The blue and red boxes are where the content returned from AJAX.Updater will be put, based on the update_method. Notice the red boxes are not in the target element, but the blue boxes are. That's the reason why append and prepend aren't enough to exactly specify where the content is going. If we wanted to limit ourselves to those two update methods, we'd have to make some up some arbitrary rules stating that the content is always inside the target element. Which could be done, but I'd rather not have that as a limitation.

Although I've gone down the path of making the update_method mimic the IE nomenclature for insertAdjacentHTML, I think different names for the update methods would clear up some of the ambiguity. The right column of the above diagram has my recommended update method names.

In short, before_begin would become before, after_begin would be top, before_end would be bottom, and after_end would be after. If this makes sense, then I think I will rework and resubmit my patch to Rails.

Any thoughts or suggestions?

Friday, March 25, 2005

Do, or do not -- never ask why

So I've been working on enhancing the, already excellent, AJAX support in Rails. But I've never really talked about the Why.

I like that Rails made AJAX so simple to use. But as I watched Sam's excellent demo, I realized that it was refreshing the entire list of 'elements' every time it returned data. Which is, as they've said, the simplest approach... But I've done that kind of thing before, and after a while the browser can bog down moving that much HTML in and out of the DOM. Not that I'm pointing fingers, but IE is especially bad about memory bloat when a lot of HTML flies around in javascript.

So, natch, I thought that it would be a good idea to cut down on as much repetition as possible and stop re-rendering every 'element' when only one has changed. Having said that, I also didn't want to over-complicate it. Especially since I just went off about certain technology groups over-architecting things.

And that is how, rather why, I got this AJAX bug up my, uh -- in my head. :-D

By the way, I'm polishing up an app I've thrown together as an example of using AJAX to only update the data that's changed. Yes, *sigh*, it is yet-another task list. But it's simple, and therefore good for an example. Plus, I'll provide the source so you can pick it apart and dig into the AJAX stuff. Look for that early next week.

The Right Way

rails_logo_remix_small.gif OK, I got the head's up that my AJAX.Updater extension wasn't happy in IE... Not too surprising, really. The XMLHttpRequest is an ActiveXObject in IE, so it doesn't like you adding spurious properties to it in JS -- which I had to do to make my enhancements just 'drop-in'.

As I was thinking about this, something I wrote in that last post annoyed me -- I talked about doing it the right way, and then I went and completely did something different. Man, I was at my last job too long.

Anyway, instead of doing something that I knew wasn't what needed to be done, I rolled up my sleeves and submitted a patch to RoR's dev site.

So, if that patch gets approved you'll be able to use a new parameter, :update_method, to indicate how you want to update the target DIV:

<%= form_remote_tag( :url => url_for( :action=>'ajax_method'), ) %>

If the update method is replace, it will replace the target DIV's content using innerHTML. Otherwise, it will add the new content positionally (without overwriting any content in the target DIV) using either insertAdjacentHTML or a DOM equivalent -- a new JS object, Insert, handles this.

Rails will pass the :update_method ( before_begin, after_begin, before_end, after_end, or replace ) to the AJAX.Updater as an option (method param). Which is the 'right way' to do it. This way we don't need to have that hacky, :loading=>'request.prepend=true;', crap.

Also, the Insert dom helper will now prefer a native implementation of insertAdjacentHTML. If it can't find one, it will revert to the DOM implementation.

Wednesday, March 23, 2005

Enhancing RoR's AJAX.Updater

So, RoR version 0.11 came out and has built-in support for AJAX. It’s very cool stuff.

A Small Bug

There was a bug in the gem I installed that may be fixed now… I’m not sure. You can have a look, the bug was in lines 61 & 62 of prototype.js (in your public/javascripts/ folder):

Toggle = {
  display: function() {
    for (var i = 0; i < elements.length; i++) {
      var element = $(elements[i]);
      element.style.display = (element.style.display == 'none' ? '' : 'none');
    }
  }
}

It should look like this:

Toggle = {
  display: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      element.style.display = (element.style.display == 'none' ? '' : 'none');
    }
  }
}

RoR’s Built-in AJAX

I really love what they’ve done with the AJAX support—it’s especially good for a first-cut. However, I’ve been playing with it and have a couple of suggestions… And code, of course.

The main thing that bothers me is the AJAX.Updater replaces the entire innerHTML of the target DOM object. I’d much rather it use an insertAdjacentHTML equivalent. Why not just use insertAdjacentHTML? Simple. Only Internet Explorer supports it. And I don’t know about you, but I avoid IE like the plague. That said, insertAdjacentHTML is an excellent way to add HTML fragments positionally in the DOM.

The Goal

So my goal was to find a way of doing this without having to hack the Rails code… Don’t wanna do it—wouldn’t be prudent.

So, to start off, what do we need? We need a nice cross-browser way of adding content in a fashion that’s similar to IE’s insertAdjacentHTML. I know it’s easy to extend mozilla’s HTMLElement... But Safari doesn’t support that. And I have to have it working on Safari.

Well, long story short, Safari can do the same thing as mozilla using HTML fragments, we just can’t extend the built-in HTMLElement class. Which is OK, really. After looking at the prototype stuff in RoR, I wanted to follow the same approach. Here’s what I came up with:

Insert = {
  before_begin: function( dom, html ) {
    dom = $(dom);
    var df; var r = dom.ownerDocument.createRange();
    r.setStartBefore(dom);
    df = r.createContextualFragment( html );
    dom.parentNode.insertBefore( df, dom );
  },
  after_begin: function( dom, html ) {
    dom = $(dom);
    var df; var r = dom.ownerDocument.createRange();
    r.selectNodeContents(dom);
    r.collapse(true);
    df = r.createContextualFragment( html );
    dom.insertBefore(df, dom.firstChild );
  },
  before_end: function( dom, html ) {
    dom = $(dom);
    var df; var r = dom.ownerDocument.createRange();
    r.selectNodeContents(dom);
    r.collapse(dom);
    df = r.createContextualFragment( html );
    dom.appendChild( df );
  },
  after_end: function( dom, html ) {
    dom = $(dom);
    var df; var r = dom.ownerDocument.createRange();
    r.setStartAfter(dom);
    df = r.createContextualFragment( html );
    dom.parentNode.insertBefore(df, dom.nextSibling);
  }
};

Cool, now we have a nice cross-browser way of adding content to the DOM in a positional way… Now we need to hook up RoR’s AJAX.Updater to use it, instead of the innerHTML approach.

A New Problem

Well, that’s all fine and dandy, but there’s a new problem: We can’t send in extra parameters in the form_remote_tag() helper method. So we have no way of telling it which position we’d like the new content to be added to the DOM.

The Right Way

Well, ideally, I think the form_remote_tag() helper should have a couple of params for handling the content returned from AJAX. Maybe you could set one of the following to true: :replace, :before_begin, :after_begin, :before_end, :after_end. Or, maybe we just have a :content_mode that would define one of the above symbols.

The Now Way

But that’s not important right now, it’s against my goal. I just want a drop-in enhancement.

Since we can’t send any params we want we need another way of telling the AJAX.Updater class how to handle the content, taking into consideration the fact it can be asynchronous… Always a fun little wrinkle.

The only thing I’ve got to work is to set it in javascript on the :loading AJAX event handler. I attach a property to the request object it sends, like so:

<%= form_remote_tag( :url =>; url_for( :action=>;'my_ajax_action' ), ) %>

Using that technique, I just created a custom AJAX.Updater.updateContent method, like this:

Ajax.Updater.prototype.updateContent = function() {
  if( this.request.transport.prepend )
    Insert.after_begin( this.container, this.request.transport.responseText );
  else if( this.request.transport.append )
    Insert.before_end( this.container, this.request.transport.responseText );
else
this.container.innerHTML = this.request.transport.responseText; if (this.onComplete) this.onComplete(this.request);
};

You’ll notice I only support prepending (adding to the beginning of a DOM element) and appending (adding to the bottom of a DOM element). It’d be a simple matter to add the other two types, I just didn’t need them.

The Script

I packaged all of this up into a single file that you can include AFTER you include prototype.js and it will automatically add all of this support.

prototype-ex.js

I’m curious to hear what you think. Plus, I’ve only really tested this on Safari, Firefox (and Camino)... It should work on any DOM compliant browser, but I haven’t gotten around to firing up my PC.

Saturday, March 19, 2005

Why Java Won't Get It Right

When I was reading DHH’spost about Rife I knew it would stir up the Javaites. And, sure enough, the first few posts were by Java trolls, lashing out and showing their ignorance.

I’ve been developing web applications for about ten years. At least four of those years have been exclusively committed to Java work. Java isn’t bad, but it isn’t great. The Sun marketing machine has made a good group of zombies, I will give it that. You’ve heard the expression ‘drinking the kool-aid’, right? You generally see it referring to pro-Microsoft people. Well the Java group are just as bad, it’s just a different flavor of kool-aid.

Now, I have a very good understanding of Java. I know that it’s not, never has been, and never will be a ‘silver bullet’. Nor has it lived up to the claim of ‘write once run anywhere’. And really, it’s no more ‘scalable’ than any other language.

I love that term; ‘scalable’. Certain people seem to think that by using Java, or .Net, or pick-your-technology, that it’s instantly ‘scalable’. Scalability is as scalability does… OK, that was a little too cheesy, but you get the point, right? It’s not the technology, but what you do with the technology that determines whether it’s ‘scalable’.

Technically speaking, everything is ‘scalable’. The question is: “Does your application code scale well when the user load is increased?”. That question is technology agnostic. The same question applies for RoR.

But I think ‘scalability’ is a red herring. You can create an application in RoR that’s as scalable as one written in Java, or .NET, or whatever technology. However, how productively can you create that application? There are people who think that LOC (Lines Of Code) are irrelevant. And, in a way, I agree. When using an IDE like IDEA, or Eclipse, you can create Java code very quickly. To me, it’s about the number of support, or boiler-plate, classes that have to be written. It’s about how much configuration is needed before you can actually use it.

But I digress. I could spend time ripping Java apart and pointing out it’s inadequacies… But that’s not the point. Every language has inadequacies. Every. Single. One. Ruby included. Java is as viable a language as Ruby, or C#, or hell, even C++. They all have their strengths, and weaknesses.

The main reason I don’t think Java will ever really have a good equivalent of RoR is because of the Java developers themselves. Before you read on, understand that these are generalizations. And no generalizations are accurate on the individual level. But, they can be indicative of behavioral patterns of a group. In others words, what I’m about to say may not apply to you—but seems to apply well to the Java community as a whole.

First, they don’t take the time to truly understands Rails. They say they do, but when you look at the ‘framework(s)’ they’ve written, it’s clearly missing the point of it all. Yes, you can do a scaffold knock-off in Java. You know what? I don’t use scaffolds at all. They are a nice add-on to Rails that can allow the developer to focus on the core of the application. Which is usually a lot more than just CRUD screens.

Second, they can’t reign themselves in. They over-architect everything. I’ve actually used a Java framework (I’m not gonna say which) that had XML config files that configured more XML config files! That’s just silly.

Huh. Well, I didn’t mean for this to become a Java bashing post. Because I like Java. I think it’s a good platform—specifically for web development. I’ve enjoyed using it over the years. It’s just a different mindset than the Rails community. And really, that’s why I think there will never be a ‘Java on Rails’. There is a fundamental difference in what each camp thinks, nay believes, is the right way of doing things.

I really meant for this to be a “why can’t we all just get along?” post. Oh well.

Update: Wow, that thread is getting pathetic. From both sides. Jeez, it’s breaking down into a contest of who has the bigger, er, framework.

Friday, March 18, 2005

WhiP it good

Well, comments just stopped working on my install of WordPress 1.2.1—for some reason. I’ve been meaning to upgrade anyway, so viola! I’m now running WP 1.5!

I’m still using the default theme—but that’ll change soon enough. Since WP 1.5 supports themes, real themes (finally!), I’ll port my old site layout to an actual WP theme.

It turns out the upgrade process was quite simple. All of the permalinks should still work. In theory. Let me know if you find problems with it…

Update: Well, I think it’s all re-stylized… It’s hard to tell the way they did the theme support. Which is, in fact, one of the main reasons I’m not a fan of PHP—it promotes spaghetti code.

Wednesday, March 16, 2005

So What Have I Been Working On?

I really can’t say enough good things about Ruby on Rails. It. Just. Makes. Sense.

Care to see what I have in the works?

Coming…. Oh, say, soon. :-)

Wednesday, March 9, 2005

AJAX and Rails

rails_logo_remix_small.gif I posted previously about communicating with Rails using XMLHttpRequest, or AJAX, as it’s starting to be called. Since that post, Rail 0.10 (and 0.10.1!) were released with the new Routes functionality.

Anyway, I’ve created a couple of JavaScript classes to aid in using the XMLHttpRequest stuff. I’ve been using them on a little project I’ve been working on (and will soon announce) and they are working great on Safari, Firefox, and Windows IE 6! I updated them for use with Routing and, being the nice guy that I am, I thought I’d share them with the world.

I call them Connectors. They connect the browser to the (Rails) server via JavaScript and XMLHttp. There are two classes, both in the same .js file: RailsConnector, and JsonConnector. They can be used Synchronously or Asynchronously.

In the aforementioned blog post, I talk a bit about the API — but the source is actually fairly well commented. It even has a couple of usage examples. So what are you waiting for? Download it!

connectors.js(8 KB)

You can use this script however you like. So have a look at it, kick the tires. I only ask that if you find any bugs, make any fixes, let me know!

Nothing New Under the Sun...

For my more GUI challenged friends, I was going to write some articles on designing web applications, usability, etc. But in my RoR trolling I came across a couple of articles that sum up, very nicely, my thoughts on design, on how design should be done.

So, without further ado, go forth and be learned:

Tuesday, March 1, 2005

A Must Read For All Web Developers

If you do any web development, you need to pick up this book:

Defensive Design for the Web : How to improve error messages, help, forms, and other crisis pointsSpecific guidelines for preventing errors in web sites and rescuing customers when problems occur, providing hundreds of real-world examples that show the right and wrong ways to handle crisis points. The book will be useful for designers and information architects, developers, copy writers, and project managers and executives.

It's a quick read, but well worth it. It has a lot of pointers that we should all follow, but we generally don't... To our own detriment.