Link to File with Extension in Rails 3

While working on a recent project I came across the need to password protect uploaded files. I was doing the uploading with Paperclip, but did not want any of the assets to live in the public folder of my application. This meant that I needed to setup my asset controller to serve out the protected files.

What I wanted was the ability to have a route that looked like http://myapp.com/assets/:id/download/:filename.ext. One of the problems I had was with the Rails router, which was not letting me pass a full filename (with the extension) as a parameter to the link helper.

In the end I came up with the following solution, which I think works quite nicely. I am using Paperclip, which should explain some of the naming conventions I've used:

# routes.rb
# Here we setup a route to handle our assets. The important thing here is the final format
# parameter contained without the parenthesis. 
match 'assets/download/:id/:attached_file_name(.:format)' => 'assets#download', :as => 'asset_download'

# application_helper.rb
# Here we take an asset object and build up our download link. Given the file "image.jpg" our
# route expects the following parameters: "id_of_object", "image", ".jpg"
#
# To make that happen we do some basic regex and use the built in Ruby File class to derive
# the extension and base filename.
def link_to_asset(asset)
  extension = File.extname(asset.attached_file_name)
  filename = File.basename(asset.attached_file_name, extension)
  link_to 'Download', asset_download_path(asset.id, filename, eextension.gsub(/\./, ''))
end

# From Any View
<%= link_to_asset(asset) %>