Edge Rails saw a barrage of refinements and enhancements this week and there's even talk about Rails 2.1 being just a little around the corner. There's also been a flurry of contributions to making Rails more thread-safe and performance optimizations (all still work in progress at the moment) - it's really nice to see how the Rails community is looking seriously at performance post-Rails 2.0 (not that they weren't serious about performance before Rails 2.0!).

This week’s report covers changes from 7 Jan 2008 to the day the corresponding Rails Envy podcast was recorded (13 Jan 2008).

X-Sendfile gets easier with send_file :x_sendfile => true

If you only have a vague idea of what it is (like, X-Sendfile is that thing that lets you send files, right?), you'd do well to read this helpful explanation. (In short, X-Sendfile allows you to send static files directly and more performantly to HTTP clients and bypassing your app server process.) You don't have to set those headers yourself or install the plugin mentioned in that article though, since edge Rails has an augmented send_file helper that does all the legwork for you.

All you have to do now is to this:

send_file '/path/to.png', :x_sendfile => true, :type => 'image/png'

Rails will set the X-Sendfile header for you (i.e. response.headers['X-Sendfile'] = '/path/to.png') and sends a HEAD response (empty response body) with the file path, allowing your web server (Apache, Lighttpd) to serve the static file and not involve your Rails processes (such as your precious, perpertually resource-starved mongrels).

This is really nice if you are serving lots of static files (downloadable images and documents come to mind) and are not already using X-Sendfile or doing it the "long" way (by setting the response header and then render :nothing => true).

Related changeset: http://dev.rubyonrails.org/changeset/8628

ActionController::Base.asset_host proc now takes the request object as an optional 2nd argument

Rails 2.0.2 allowed you to set ActionController::Base.asset_host to a proc that took a single source argument (as detailed in my earlier post). People were still running into problems with asset hosting though, particularly while trying to serve assets from an SSL-protected page (i.e. HTTPS requests). When serving SSL-protected pages, you'd need to either have an SSL certificate for each asset host(!) or live with a mixed media warning (which browsers report when you have SSL and non-SSL content on the same page).

The asset_host proc now takes the entire controller request instance as an optional second argument. This allows you to either use a single asset host or to disable asset hosting for SSL requests. For example, this proc below practically disables asset hosting:

ActionController::Base.asset_host = Proc.new { |source, request| 
  if request.ssl? 
    "#{request.protocol}#{request.host_with_port}" # Disable asset hosting.
    "#{request.protocol}assets.example.com" # Use asset host.

Related changeset: http://dev.rubyonrails.org/changeset/8578

Nicer way to access request headers

There's now a nicer way to access headers - instead of request.env["HTTP_CONTENT_TYPE"] you can now do request.headers["Content-Type"] (or request.headers["content-type"] (note all lowercase) or even good old request.headers["HTTP_CONTENT_TYPE"]. How convenient - I often worry about getting the casing right (was it 'Content-Type' or 'Content-type'?) and now I can be sure it doesn't matter!

Related changeset: http://dev.rubyonrails.org/changeset/8625

ActiveSupport::TestCase and friends now support declarative setup and teardown callbacks

ActiveSupport::TestCase (and the ActionController::TestCase and ActionMailer::TestCase subclasses) now support declarative setup and teardown callbacks that are called before setup/after teardown. For example,

class FooTestCase < ActiveSupport::TestCase
  setup :run_this_first, :then_run_this do
    # Run this last.
  teardown :remove_tmp_files, :undef_constants

  def run_this_first

  def then_run_this

  def remove_tmp_files

  def undef_constants

will run run_this_first, then_run_this, and finally the stuff that's in the given block to 'setup' before running the actual setup method. The teardown callbacks are done in reverse order, meaning undef_constants is called, and then remove_tmp_files (and then the actual teardown method).

Related changeset: http://dev.rubyonrails.org/changeset/8570

TMail updated to 1.2.1

The bundled TMail library (that ActionMailer uses) has been updated from 1.1.0 to 1.2.1. This new version currently maintained by Mikel Lindsaar promises bugfixes and greater test coverage. For more details, see https://rubyforge.org/frs/shownotes.php?group_id=4512&release_id=18049.

Mikel has been working with Rails core to get Tmail Ruby 1.9-compatible. Good work Mikel!

Related changeset: http://dev.rubyonrails.org/changeset/8620

Bug fixes

  • ActionController::UrlWriter respects the relative_url_root. For those of you who don't know, the ActionController::UrlWriter module is a convenient mixin that allows you to use url_for and your named routes in arbitrary classes (such as in your mailers or in a BackgrounDRb worker).

    class SitemapWorker < BackgrounDRb::MetaWorker
      include ActionController::UrlWriter
      # Access your named routes and the url_for helper.
      url = page_url(:permalink => 'foo')

    And now it respects your relative_url_root instead of blissfully ignoring it.

    Related changeset: http://dev.rubyonrails.org/changeset/8616

  • render :text => nil and render :text => false work properly now instead of inexplicably trying to render a file. This was a big gotcha when using render :text => some_variable where some_variable could potentially be false or nil in some cases - Obie Fernandez has a writeup on this long-standing bug. Related changeset: http://dev.rubyonrails.org/changeset/8577


There're significant performance improvements for classic fixtures with HABTM data, due to some slightly clever caching model classes, and instantiating fixtures from the model class, instead of expensive constant lookups from the name of the class.

Related changesets: http://dev.rubyonrails.org/changeset/8560 and http://dev.rubyonrails.org/changeset/8561