YSlow is a Firefox extension that works with Firebug to grade your web pages’ performance and gives you advice on how to fix any problems. Awesome. It has JSLint built into it too. And yes I got a big freaking F. Via Arun (IRL). (3)

MySQL command line “secret”

Tom Preston-Werner (of Gravatar and Chronic fame) wrote about this neat MySQL command line “trick” where instead of ending your SELECT statements with the usual semi-colon, using a “\G” gives you a very readable output.

mysql> select * from locations where location_code = 'SIN'  limit 1\G
*************************** 1. row ***************************
          location_code: SIN
          location_name: Singapore Changi Apt
multi_airport_city_code: SIN
          location_type: A
      location_sub_type: A
           country_code: SG
             state_code:
                 active: 1
               latitude: 01.22.00N
              longitude: 103.59.00E
1 row in set (0.10 sec)

Very useful, especially when SELECTing multiple fields where the output becomes unfit for visual consumption (you know what I mean, just go SELECT some stuff in your MySQL command line and you’ll see if you don’t).

God and your web server

God is a new process monitoring Ruby framework with a rather apt name (no, it’s not that God). The config files looks something like that:

God.meddle do |god|
  god.watch do |w|
    ...
  end
end

Interesting code to write. And feels safe too to have God watching over your mongrels. Oh and you can use it to clean up stale mongrel PID files without patching mongrel_rails. Right now I use monit a lot and it’s really rather unDRY to have repeated configs for each mongrel on the server (is there a better way of doing this in monit?). God would be able to DRY it up.

Better JSON output from Rails with the Jsonifier plugin

Update: Edge Rails now does whatever Jsonifier does (and more). Check out my blog post on JSON serialization maturity in edge Rails. This means that this plugin is virtually obsolete if you’re using edge Rails.

If you’ve tried to output JSON from your Rails applications before, you’d probably have noticed how inadequate it all seems. Let’s look at the kind of output (pretty-printed for easier reading) you get from calling to_json on your typical User model:

{
  attributes: {
    id: 1,
    name: "Konata",
    awesome: true,
    created_at: "07/01/2007"
  }
}

Some of the common problems developers who write applications that speak JSON have with this are:

  • The attributes part is often unnecessary cruft when consuming ActiveRecord objects as JSON.
  • There’s no obvious way to control which attributes are shown in the JSON (e.g. you may want to hide private or lengthy attributes). The way to workaround this is either to write your own to_json instance method for your ActiveRecord model, or to use a Rails plugin (like acts_as_json) or a gem.
  • Including 2nd (or higher order) associations is tricky (as above, you can achieve this by defining your own to_json instance methods).

Under the hood of the current ActiveRecord#to_json

The to_json method for ActiveRecord objects falls back on using that defined in ActiveSupport’s JSON classes. The way it’s currently done, there are a bunch of JSON encoder classes defined for various types - when you call to_json on an ActiveRecord object it simply uses Object#to_json.

By the way, see that created_at: "07/01/2007" bit in the example above which is the JSON output for a Date attribute? That’s in MM/DD/YYYY format. Yup, 1st July 2007 not 7th January 2007 you “rest of the world you”. Ouch, but at least you can use JavaScript’s Date.parse() on it directly as detailed in this patch. And before you ask, yes, Date.parse() doesn’t understand the YYYY-MM-DD format.

Can has Rails patch?

So about 2 days ago, I wrote a Rails patch to boost ActiveRecord#to_json with an options hash. Yep much like what you can do with ActiveRecord#to_xml.

I hope it gets committed into the core some day. I mean, gosh, isn’t Rails all about Web 2.0 mashups. It even has that fancy render :json thing. I do believe JSON output needs to be treated more seriously in Rails rather than the half-hearted attempt at JSON encoding. No? Well, if the patch doesn’t get accepted I’ll still have my plugin (see below).

Anyway, let’s see some examples:

Some examples, see?

Assuming User and Post models where User has_many Posts:

david = User.find(1)
david.to_json  # {id: 1, name: "David", awesome: true, created_at: "07/01/2007"}

No more attributes cruft!

:only and :except work the same way that as for ActiveRecord#to_xml:

david.to_json(:only => :name)                 # {name: "David"}
david.to_json(:only => [:id, :name])          # {id: 1, name: "David"}
david.to_json(:except => :created_at)         # {id: 1, name: "David", awesome: true}
david.to_json(:except => [:id, :created_at])  # {name: "David", awesome: true}

You can use the :methods options as well to include any methods on the object.

david.to_json(:methods => :permalink)
  # {id: 1, name: "David", awesome: true, created_at: "07/01/2007", permalink => "1-David"}
david.to_json(:methods => [:permalink, :interestingness])
  # {id: 1, name: "David", awesome: true, created_at: "07/01/2007", \
  #   permalink => "1-David", :interestingness => 666}

The :include option lets you include associations.

david.to_json(:include => :posts)
  # {id: 1, name: "David", awesome: true, created_at: "07/01/2007", \
  #    posts: [{id: 1, author_id: 1, title: "Welcome to the weblog"}, \
  #            {id: 2, author_id: 1, title: "So I was thinking"}]}

:only, :except, and :methods works on the included associations as well:

david.to_json(:include => { :posts => { :only => :title } })
  # {id: 1, name: "David", awesome: true, created_at: "07/01/2007", \
  #    posts: [{title: "Welcome to the weblog"}, \
  #            {title: "So I was thinking"}]}

Of course, 2nd level (and higher order) associations work too:

david.to_json(:include => { :posts => { \
                              :include => { :comments => { \
                                              :only => :body } }, \
                              :only => :title } })
  # {id: 1, name: "David", awesome: true, created_at: "07/01/2007", \
  #    posts: [{comments: [{body: "1st post!"}, {body: "OMGWTFBBQ!"}], \
  #             title: "Welcome to the weblog"}, \
  #            {comments: [{body: "Don't think too hard"}], \
  #             title: "So I was thinking"}]}

Please do give any feedback at the Rails patch for ActiveRecord#to_json or here. I wanna know what you feel about adding this functionality into the Rails core!

Jsonifier plugin

I’ve rolled the patch into a plugin: Jsonifier. The Jsonifier Trac is at http://trac.codefront.net/jsonifier/.

Subversion repository:

svn://svn.codefront.net/jsonifier/trunk

To install the plugin:

ruby script/plugin install svn://svn.codefront.net/jsonifier/trunk

A note on valid JSON

The JSON Rails spits out by default is not strictly valid JSON since the JSON specifications require keys to be double quoted. To get strictly valid JSON, add

ActiveSupport::JSON.unquote_hash_key_identifiers = false

in your environment.rb (or in the Rails initializers directory if you’re on edge). See my blog post on how to get strictly valid JSON from Rails for more info.

Read the bug fix announcement. Upgrade! This was causing extremely puzzling crashes in Safari on Macs (pre-Safari 3 beta) on one of our applications and I’m glad (in some ways) that the problem lay with the Prototype library. (2)