Thursday, February 19, 2009

Ext JS, Checkboxes, and Ruby on Rails

I am currently building a web application that makes heavy use of wizards and forms built with Ext JS. I am sending the form's values as JSON over to a Ruby on Rails server. Thanks to Rails 2.2.2, the JSON is automatically converted into an parameter hash.

For a little background to the problem I am about to describe, HTML checkboxes are notoriously difficult to work with, because if the user does *not* check the box, then the browser will not send a value when the form is submitted. This makes it difficult to handle a state change from checked to unchecked.

Rails makes this a bit easier because it will render both a hidden field with a value of "off" as well as the original checkbox. If the user checks the box, both values are sent but Rails will use the value from the checkbox (and not the hidden field). If the user does not check a box, only the hidden field's value is sent, which means the "off" value is sent.

However, when using Ext JS to render the form and its checkboxes, no hidden "off" field is rendered. Our first inclination is to extend the checkbox component to also render a hidden "off" field, much like Rails. However, because I am serializing the form as JSON, this strategy breaks down because the serialization will create an array of values for the checkbox and hidden field combo. This is because the fields are both named the same thing (exactly what the Rails code does) and when form serialization occurs, it will create an array if it encounters more than one value for a field name.

Instead of rendering a hidden "off" field for checkboxes, I simply change the way I am serializing the form. After serialization, I loop back through the form, find all the checkboxes, and for those checkboxes that are unchecked, I add an "off" value into my JSON serialization.

The code for this is much more simple than it sounds, and lets me always send checkbox values, regardless if they are checked or unchecked.

var serializedForm = card.getForm().getValues(false);

// because unchecked checkboxes do not submit values, manually force a value of 0
card.getForm().items.each(function(f) {
if (f.isFormField && f.getXType() == 'checkbox' && !f.getValue()) {
serializedForm[f.getName()] = '0';
}
});

Sunday, February 1, 2009

Rails Builder Is Slow But Easy To Fix

For the impatient: Go install the fast_xs gem if you use Builder in Rails.

The long story:

I was using New Relic RPM to watch Errorlytics, and noticed everything was humming along just fine, except... the Atom feed of new 404 errors was taking an extremely long time. Request times of 800ms were not uncommon. RPM told me that the view rendering was taking most of the time, which made sense because I had already ensured that all the queries were by index.

Errorlytics uses the Atom Builder to construct the Atom feed, and generally I like it. However, I had my doubts after learning it was the bottleneck, and I was hoping I wouldn't have to rip it out and write the XML by hand.

After a bit of Googling around, I was lucky enough to run across Speed up your feed generation in Rails. This post details the same issue, in that the Builder had some major performance issues. Thankfully, the author of that post did all the hard work. They learned that installing the fast_xs gem is the quickest and easiest way to speed up Builder output. Fast_xs implements a common bottleneck as native code, with impressive results.

Bottom line, if you're using Builder in Rails 2.0.2 or later, you should go install fast_xs gem and link it to your Rails application via config.gem 'fast_xs. Your site will thank you.

Disclaimer

I'm probably required to say that the views expressed in this blog are my own, and do not necessarily reflect those of my employer.