nosewheelie

Technology, mountain biking, politics & music.

Archive for the ‘asset’ tag

Serving Javascript using Rails’ asset hosts

without comments

I’ve not seen this anywhere in my various googling, so thought I’d post it in case it’s useful to anyone.

As a graphically rich site, Scoodi serves a lot of static content to a client browser; images, CSS and Javascript. We recently moved to using asset servers in order to speed up the total download time, however this had an unexpected side-effect in some versions of Internet Explorer, we got security warnings from our rich-text widget (TinyMCE), which meant members could not create new items or edit existing ones in IE.

We managed to resolve this by serving Javascript files without a host, meaning that they’d be resolved relative to the page (so inherit its scheme, host, port, etc.), however this involved a change to some internal Rails code, not something we’d like to maintain.

However fixing it in a generic way proved to be quite easy. Rails 2 lets you pass a function as an asset host, which gets invoked when an asset host is needed. This function gets passed the source (the images, etc. requested) and in the HEAD of the trunk of asset_tag_helper.rb it also (optionally) gets passed the request.

So, here’s the quick solution, added to the appropriate environment file. We only serve non-Javascript files from asset servers, and we also don’t use an asset server for SSL requests (avoiding mixed content warnings in some browsers).

config.action_controller.asset_host = Proc.new do |source, request|
  request.ssl? || source =~ /javascripts/ ? "#{request.protocol}#{request.host_with_port}" : "http://asset#{source.hash % 4}.scoodi.com"
end

There is another to give Rails the no-asset server host, by replacing "#{request.protocol}#{request.host_with_port}" with "" (the empty string). This however has a number of problems, 1) you don’t explicitly know which host is being used, which may cause problems over SSL (we haven’t reached an SSL-aware environment at the time of posting, so I can’t confirm this) and 2) it relies on the internals of asset_tag_helper.rb, where "" is treated as “don’t use the host provided”.

config.action_controller.asset_host = Proc.new do |source, request|
  request.ssl? || source =~ /javascripts/ ? "" : "http://asset#{source.hash % 4}.scoodi.com"
end

For both these reasons we originally decided to go with explicitly listing the scheme, host & port to use. However, we’ve had some issues when connecting to the site using an alternate address (say the machine’s IP address), the address that gets returned (request.host_with_port) returns a hostname that makes sense on the machine (running Rails) but may not be resolvable by the client (browser). Not using the hostname (returning the empty string) will cause Rails to not append a host (e.g. src="/javascripts/foo.js"), causing the browser to resolve the assets relative to the page, which will take into account the (correct) address of the server as requested by the browser. Good stuff.

Written by Tom Adams

May 7th, 2008 at 8:32 am

Posted in Ruby

Tagged with , ,