Tuesday, August 16, 2011

Rails incorrectly parses HTTP Accept header for single media with range

Try hitting your Rails app with an HTTP header like this:

Accept: text/html;q=0.7



You will most likely get an exception that looks something like this:

Missing template home/index with {:locale=>[:en, :en],  :formats=>["text/html;q=0.7"], :handlers=>[:rhtml, :erb, :haml,  :rxml, :builder, :rjs]} in view paths  "/path/to/my_app/app/views"



This is because the ActionPack Mime::Type class is buggy in the way it parses this header when there is only one media type specified, and that media type has a range specified (the ";q=0.7"). This is perfectly valid HTML, and ActionPack actually handles the ranges correctly when there are more than one type specified.

An issue has been open for a while on this: https://github.com/rails/rails/issues/736 -- working patches have been proposed but not applied, yet the issue got closed for some reason.

I prefer not to patch my own version of Rails, so instead I am using a small monkey patch that works around this problem. I've created a file named config/initializers/rails_issue_736.rb that fixes the Mime::Type.lookup method to only use the part that comes before the semi-colon:


Monday, August 15, 2011

MailMatic: HTML emails using Haml and Sass

Developing static HTML emails is a pain in the butt. For best results, you need to inline all of your styles at HTML attributes instead of using real CSS (externally or inline). You also typically find yourself being very repetitive with your markup if you have a bunch of static emails that share common elements.

MailMatic to the rescue.

MailMatic is a Ruby gem, that is really just a mashup of tools, that aims to ease the burden of creating and maintaining static HTML emails. It uses StaticMatic, Haml, Sass, and Compass to let you author your HTML emails with all of the facilities you enjoy while creating your dynamic site: templates, partials, helper functions, inline Ruby code, reuse of markup and styles, etc. It uses Premailer to convert the HTML/CSS generated from Haml/Sass into self-contained HTML files that inline all of their styles. Premailer even gives you warnings about styles that may not work nicely in certain email readers.

Armed with this, you can accelerate your ability to crank out static HTML emails, and lessen the burden of maintaining them.

To get started with MailMatic, check out its installation and usage instructions on github at: https://github.com/scottwb/mailmatic.

Tuesday, July 19, 2011

The ask_geo gem: find the time zone for a given latitude and longitude




The Google Maps API has all kinds of great services like geocoding and reverse geocoding, but it lacks an API to determine a timezone from a latitude and longitude. This kind of service would come in handy, for example, when you are picking a point on Earth and scheduling an event there in the point's local time. It could also be useful for automatically determining a website visitor's current local time based on the geolocation obtained from their browser or IP address.

There is a service called GeoNames, which comes close to serving this need. However, its look-ups are based on "closest point of interest", which means that you can get errors when you are near borders, and some locations may not return any results at all.

There is another service called EarthTools which doesn't have this problem, but it only returns the current offset from UTC at that point. That is great if you only care about the current local time, but leaves you stranded if you need to account for Daylight Savings Time on some future or past date.

After a bit of searching, I came across a great free service called AskGeo. AskGeo provides a very simple JSON-over-HTTP API (or XML if you prefer to party like it's 1999). AskGeo uses a real time zone map, so every point on earth returns a result, and returns real Olson IDs for time zones, so you can look up DST transitions, leap seconds, etc.

I gave AskGeo a try and it works great...and it's fast! Since there was no ready-made Ruby gem that provided a client API, I decided to create one.

Introducing the ask_geo gem: https://github.com/scottwb/ask_geo

It can be installed as a ruby gem. See the github page for installation and usage instructions.