Watch out for the Monkey Patch

The project I’m currently working on uses both the Asset Packager and Distributed Assets to ensure we have only a few external assets, and that we can load assets across more than one host - all so that the pages for our site load nice and quick.

Unfortunately, wiring in the Asset Packager plugin caused the Distributed Assets plugin to break, and I spent an hour or two tracking it down yesterday. The cause? Asset Packager redefines the compute_public_path method.

# rewrite compute_public_path to allow us to not include the query string timestamp    # used by ActionView::Helpers::AssetTagHelper    def compute_public_path(source, dir, ext=nil, add_asset_id=true)      source = source.dup      source << ".#{ext}" if File.extname(source).blank? && ext      unless source =~ %r{^[-a-z]+://}        source = "/#{dir}/#{source}" unless source[0] == ?/        asset_id = rails_asset_id(source)        source << '?' + asset_id if defined?(RAILS_ROOT) and add_asset_id and not asset_id.blank?        source = "#{ActionController::Base.asset_host}#{@controller.request.relative_url_root}#{source}"      end      source    end

Distributed Assets works by chaining compute_public_path - decorating the calculated path, adding the asset host prefix onto the url. But, Asset Packager works by defining the method into ActionView::Base. So, when DistributedAssets::AssetTagHelper is included with ActionView::Helpers::AssetTagHelper, it chains a (now) hidden method.

But, the only places that use the new compute_public_path code inside the Asset Packager Helper (which just avoids using the query string timestamp) is within Asset Packager itself.

So, I tweaked the implementation of AssetPackageHelper to

def compute_public_path_for_packager(source, dir, ext, add_asset_id=true)  path = compute_public_path(source, dir, ext)  return path if add_asset_id  path.gsub(/\?\d+$/, '')enddef javascript_path(source)  compute_public_path_for_packager(source, 'javascripts', 'js', false)       end

Beware the monkey patch.