Sparkline graphs using data: URIs

A while back, I ran across sparkline graphs, created by Edward Tufte for displaying data visually in a very compact space, usually inline with text. Google uses these extensively in their Analytics product, and it seemed like a great fit for representing data on the ZingLists administrative dashboard.

There are two easily found implementations of sparkline graphs for Ruby: Sparklines and Bumpspark. Bumpspark is nice because the graphs use data: URIs and don’t require any extra parts server-side, but the Sparklines plugin offers far more drawing options.

Why not the best of both? Here is a modified sparkline_tag method for Sparklines, which accepts a new option, :inline_data. When true, it emits a data: URI instead of a reference back to your server. I like this for several reasons: it loads faster, it doesn’t require a new controller, and it doesn’t require a new route if you’ve done away with the generic /:controller/:action/:id and are using RESTful routes.

require 'base64'
 
  def sparkline_tag(results = [], options = {})
    tag_options = { :class => (options[:class] || 'sparkline'),
                    :alt => "Sparkline Graph" }
    if options.delete(:inline_data)
      tag_options.merge!(:src => "data:image/png;base64,#{Base64.encode64(Sparklines.plot(results, options)).gsub("\n", "")}")
    else
      url = { :controller => 'sparklines', :results => results.join(',') }
      tag_options.merge!(:src => url_for(url.merge(options)))
    end
    tag(:img, tag_options)
  end

Update: When I emailed this to Geoff (who maintains Sparklines), he reminded me that IE doesn’t support data: URIs, so :inline_data isn’t useful if your pages need to display in IE.

Collecting Statistics from PostgreSQL in Rails

The PostgreSQL database includes a statistics collection facility that can give you information about your database, tables, indexes and sequences. I just posted a new Rails plug-in that makes it very easy to gather this information and display it in a Rails application.

pgsql_stats screenshot

All of the counters described in the PostgreSQL manual are represented in the models in the plug-in. To name a few:

  • Number of scans over the table or index
  • Cache hit/miss counters (and cache hit rate, by a simple computation)
  • On-disk size

In the above screenshot (taken very soon after the server was started), it’s easy to see that the cron_runs table is by far the largest in the database, followed by its primary key index. Of the entities that have been touched, a large percentage of requests are being satisfied by the buffer cache. You can’t see it in that image, but I’ve defined ranges that turn the green bars red if the cache hit rate falls below 75%.

I’ve set up a Google Group forum for further discussion. Some additional information is available in the README, and the plug-in can be installed like any other:

$ script/plugin install \ http://svn.lightyearsoftware.com/svn/plugins/pgsql_stats

All on one line, of course.

Update Sep. 10, 2007: There is now a usage example on the Google Group that shows how to get the results shown in the screenshot.

Update Jul. 23, 2008: Part of the fallout of Google disabling my account appears to be that the group I set up for discussion and support disappeared, too. I have moved discussion and support to my own forums: pgsql_stats forum.

Inheritance in ActiveRecord, without STI

One of the few times Rails let me down while developing ZingLists was how it deals with class inheritance in ActiveRecord. Actually, unless you want Single-Table Inheritance semantics, you may as well pretend it doesn’t exist, because I couldn’t find a clean way to do it.

Here was my particular problem:

Out of the box, Rails likes to construct URLs that usually end with a numeric ID when you’re dealing with resources. There is a method, to_param, that the URL helpers call when they want to turn an object into an ID suitable for a URL.

Conventional wisdom says that Google likes URLs that are meaningful. A string of numbers at the end doesn’t mean anything, which is why you often see URLs ending with a snippet from the page title. Blogs often do this (just look at the top of this page, if you’re not reading from the index).

So, to get nice URLs, modify to_param. But what if you only want to do it some of the time? Inheritance usually solves this problem: customize in the derived class. But ActiveRecord forces STI on you if you do this, and maybe you don’t want that.

In ZingLists, I have a single table, lists, that contains all of the lists in the system, whether they are private lists for a member or lists that a member has published to the community. It pretty much has to be this way, since publishing a list does not fix it in time. The member may (and probably will) continue to use it for themselves, and if they add to it, I’d like those changes to be available in the public view immediately, with no extra work.

I want public list URLs to be nice for Google, but don’t have any desire to junk up private list URLs, too. How to solve this problem?

Duck Typing. The URL helpers don’t care what kind of class you hand them, as long as it responds to to_param:

class PublicList
  def initialize(list)
    @list = list
  end
 
  def to_param
    "#{@list.id}-#{@list.name[0..29].tr_s(" ", "-").gsub(/[^-a-z0-9]+/i, "")}"
  end
end

Now, when I want to create a pretty URL for Google’s benefit, I just have to instantiate a wrapper around the real object:

public_list_path(PublicList.new(list))

(Wishful thinking: What would be really neat is a facility where you can get STI-like semantics, but provide your own definition of how to differentiate between the types of object, rather than have it hard-coded to a column called “type” that contains a string representation of the class to instantiate.)