Friday, March 5, 2010

Missing images with JQTouch on Rails Production

It's generally a good idea to use the ":cache=>true" argument to stylesheet_link_tag to ensure that all your stylesheets are loaded in a single request in production. Eg:


= stylesheet_link_tag '/jqtouch/jqtouch.min.css', '/themes/apple/theme.min.css', 'mobile', :cache=>true

This can cause problems though if the stylesheet:
  1. References resources (such as background images) via relative URLs
  2. Lives somewhere other than public/stylesheets
The reason it's a problem is that the :cache=>true option causes stylesheet_link_tag to bundle all listed stylesheets into /public/stylesheets/all.css. Suddenly, every URL is relative to public/stylesheets.
I encountered this problem when using JQTouch in a Rails app.

The theme stylesheet for jqtouch was located in /public/themes/apple/ and it expected to find all images in an img sub-folder. This worked fine in development but in production, suddenly no images appeared.

My fix for this was simply to create a symbolic link in the stylesheets folder thus:

cd stylesheets
ln -s ../themes/apple/img img

This seems to do the trick, even on Heroku.

Ruby Dates to Javascript the Easy Way

Whilst writing the queue management for Cafebop in Javascript using the excellent JQTouch library I came across a problem that I thought would be trivial to solve. In the end it was trivial but maybe it's so trivial that nobody ever mentions it so I couldn't find any info on it.

Basically, I wanted to instantiate a Javascript Date object from a Ruby Date object via a JSON call. The problem is that Javascript's Date object constructor can't parse the default string output by Ruby's Date#to_s.

However, it can parse an integer which is milliseconds since the Unix epoch. Ruby's Date#to_i outputs the number of seconds since the unix epoch. So, using my mad arithmetic skillz, I figured I can create a Javascript Date with:

new Date(rubyGeneratedInteger * 1000);

So my usage of it went something like this. In my rails model, I generate an appropriate integer representation of the timestamp:



I make that available to a JSON client through the controller:

And consume it from the Javascript client thus: