Adding extra params to rails route resources

There's no good way to remove the controller/id part of a resource. The closest you're going to get through tricking ActionController with something like this:

map.resources :gray, :path_prefix => "/images/:product/:image_id/", 
  :controller => 'images', :requirements => {:colour => "gray"}

Which will produce routes like www.site.com/images/product/4/gray/1234.html with the following params hash:

params => { 
  :image_id => 4,
  :id => 1234,
  :colour => "gray",
  :product => "product"
}

The format won't be passed explicitly but it will be available in the controller through the usually respond_to means.

Next you'll have to work some magic in controller to trick rails into doing what you want.

class ImagesController < ApplicationController
  def show
    @size = params[:id]
    @image = Image.find(params[:image_id])
    ...
  end
end

This actually works better as a filter so:

class ImagesController < ApplicationController
  def initialize_colour
    unless params[:colour].nil?
      @size = params[:id]
      @colour = params[:colour]
      @image = Image.find(params[:image_id])
    end
  end

  before_filter :initialize_colour, :except => [:index, :new, :create]

  ...

end

However to make good use of these routes, you're going to have to pass all those extra parameters to your url for calls. Like this:

gray_url(size, :image_id => @image.id, :product => product)

But helpers make that easy.

module ApplicationHelper
  def easy_gray_url(image, size, product)
    gray_url(size, :image_id => image.id, :product => product)
  end
end

Check out the documentation for Resources. You'll find this:

The resources method accepts the following options to customize the resulting routes:

  • :requirements - Set custom routing parameter requirements; this is a hash of either regular expressions (which must match for the route to match) or extra parameters. For example:

    map.resource :profile,
                 :path_prefix => ':name',
                 :requirements => { :name => /[a-zA-Z]+/, :extra => 'value' }
    

    will only match if the first part is alphabetic, and will pass the parameter :extra to the controller.