Ruby, iOS, and Other Development

A place to share useful code snippets, ideas, and techniques

All code in posted articles shall be considered public domain unless otherwise noted.
Comments remain the property of their authors.

2007-01-22

The Dread Comma

Consider the following scrap of code from a Rails helper method:

  hash = { :id => result.id,
    :title => result.name,
    :addr => result.foo }
  hash[:foo] = controller.send(:render_to_string, {:partial => "foo", :object => hash}),
  hash.merge!(more_params(result))
  hash.to_json

That code raises a JSON::CircularDatastructure exception. Here is the corrected code:

  hash = { :id => result.id,
    :title => result.name,
    :addr => result.foo }
  hash[:foo] = controller.send(:render_to_string, {:partial => "foo", :object => hash})
  hash.merge!(more_params(result))
  hash.to_json

The difference is a single comma at the end of the fourth line. Without that comma, the code works as expected. In sequence, a literal hash is declared, an additional key-value pair is added, and a hash returned by a method call is merged in. With the comma, however, hash[:foo] is set to a two-element array. The first element is what we intended and the second is the hash itself, creating a recursive (a.k.a. circular) data structure. I am too embarassed to admit how long it took me to figure out what was going on.

Forewarned, may you never encounter such a bug in your own code. Enjoy!

Labels: , ,

2007-01-03

AJAX and Graphs

I just finished a post in which I promised some technical info about part of the site I worked on. This is more about JavaScript (and prototype) than it is about Rails, but I'm hitting the server for data, which means it's involved.

Consider a really simple CSS bar graph (with inline styles for blogging convenience):

Now suppose you wanted to update that graph via AJAX. The Rails way would be to use a prototype Ajax.Updater to replace the table with new HTML generated on the server side. That's workable, and easy to program, but it involves a larger payload from the server and more processing on the server side. All the client needs is the height of the bars, and the CSS change can be performed in JS. So consider a JS function (apologies for lack of highlighting; the syntax gem doesn't support JS):

function updateGraphs(req) {
  var data = eval('('+req.responseText+')');
  var bars = Element.getElementsBySelector('graph', 'td');
  if (data.length != bars.length) {
    alert("Length mismatch: there are "+
      bars.length+" bars and "+data.length+" returned heights.");
    return;
  }
  for (var i=0;i<data.length;++i) {
    var height = data[i];
    var margin = 100-height;
    Element.setStyle(bars[i],
        { height: ""+height+"px", "margin-top": ""+margin+"px" });
  }
}

All you need back from Rails is an array of integers in JSON. You're all done in one line of Ruby/Rails:

render :text => @data.to_json, :type => "text/javascript"

A quick Ajax.Request with the proper parameters and the JS function above, and you're all set on the client side. To see a fancier version of this in action, look at this. If you haven't registered for the site, you'll need to do so through this link.

Enjoy!

Update: We're using Flash now instead of the CSS graphs. Oh, well.

Labels: , ,

Shameless Promotion: Revolution Health

I work for a company known as Revolution Health. It was founded by Steve Case, of AOL fame, to "revolutionize health care" and make it easier for consumers to deal with the health care system. I think it's a noble mission, and might even succeed, but I'm a geek so I'm mostly excited about working on the largest Ruby on Rails project yet. (No, I can't back that up with specific numbers, but I'm telling you it's big.)

If you're reading this blog, you're probably more interested in the technical details (many of which I can't disclose) than the site itself, but I encourage you to take a look anyway. It's in preview mode, which means that you can't see it without registering (registration will always be free), and you can't register without being invited. Well, I'm inviting you. Use this link to register and take a look around. If you have trouble registering or with the site in general you can call 800-990-2892 or email customercare ATT revolutionhealth DDOT com (trying to avoid spam...).

In the next post I'll give a bit of technical info on one of the things I did. I can get away with telling you about it because it's nothing you couldn't figure out with Firebug and a little work.

Labels: