Restful Resource routes with parameters and page caching

I'm trying to set up a restful route where an Album resource has a singletone Artwork resource. Sounds simple enough:

map.resources :albums do |album|     album.resource :artwork,       :controller => 'artwork', :format => 'jpg'   end

With the above routing config, /albums/xxx/artwork.jpg works as expected.

However, my artwork controller also has an option to resize the image if a :size parameter is given. This also works:

/albums/xxx/artwork.jpg?size=100

However, I want to cache the resized artwork using Rails caching. Adding caches_page :show works and the cached file is saved under public/albums/xxx/artwork.jpg.

But what about when I specify a size? I want these to be cached individually. Specifying size as a query string parameter means the size is ignored when caching takes place (it is always stored as artwork.jpg). What I really need is to be able to move the size parameter into the URL, so it looks something like this:

/albums/xxx/artwork/size.jpg

This would mean page caching does what I want it to do. However I cannot see any easy way of moving size into the URL using map.resource. I can set up a custom route but any restful url helpers take no notice of it. Can anybody help me with this?

Umm..I'm not a fan of nested resources, so I don't know how this would behave here, but try using path_prefix

map.resources :albums do |album|    album.resource :artwork, :controller => 'artwork', :format => 'jpg', :path_prefix => ':size' end

I'm not sure that path_prefix is what I need here; either way, I managed to get this working by treating size as another resource under artwork. So in essence:

An album has ONE artwork (singleton resource).

map.resources :albums do |album|   album.resource :artwork end

That single piece of artwork can be represented in a number of different sizes (could be fixed, but in my case its arbitrary):

map.resources :albums do |album|   album.resource :artwork do |artwork|     artwork.resources :size   end end

However, because the controller code to resize the image was so simple (it was all abstracted to the model layer), I was able to handle both the singleton artwork resource and its various sizes with a single ArtworkController#index action:

class ArtworkController < ApplicationController   before_filter :load_album   caches_page :show

  def show     @artwork = Artwork.new(@album, size = params[:id])

    send_data @artwork.to_blob,       :disposition => 'inline',       :type => @artwork.content_type   end

  private     def load_album       @album = SlimServer::Album.find(params[:album_id])     end end

The only thing here that is slightly confusing is that the size we want arrives as params[:id]; this wouldn't be so confusing if I was using a separate AlbumSizesController I guess so I can live with it (hence I've added the variable hint to the parameter).

The final routing config, with controller names and formats specified is:

map.resources :albums do |album|   album.resource :artwork, :controller => 'artwork', :format => 'jpg' do |artwork|     artwork.resources :sizes,       :controller => 'artwork', :format => 'jpg'   end end

I can now access the raw unaltered artwork using /album/xxx/ artwork.jpg and a specific size at /album/xxx/artwork/sizes/xxx.jpg.

Hope this helps anyone with a similar issue.

Small correction the above post, the following block of code should have artwork.resources :sizes (plural).