views:

533

answers:

3

What I want to do seems simple, but might not be "proper"

let's say I have an image resource, and I manipulate the image based on the url. In the url I want to specify it's size and whether it's grayed, colored, or dimmed or some other condition.

currently I have a number of named routes that look like this.

map.gray_product_image "images/:product/:image/gray/:size.:format", :controller => 'images', :action => 'gray_product_image'

for me the trick is that if I created this useing Rails resources, I don't know how I would specify the :size, :format, or it's "color type".

I guess I would like to add a member route and specify my params like the following.

map.resources :products do |products| 
  products.resources :images, :member => {:gray_product_image => {':image/:size.:format' => :get}}
end

There are other times where I have wanted to added extra info to a resource route but didn't know how.

Any help would be greatly appreciated, Thanks.

+1  A: 

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.**

Steve Klabnik
Right, but how can I add ':size' to the end of my url, but before the :format option
ToreyHeinz
+1  A: 

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
EmFi
This is helpful in thinking through what I am really trying to do, and what I have come to is this... it's not worth it.
ToreyHeinz
You have two other options: Write your own version of map.resources and or write method that generates a the required named_routes.
EmFi
Thanks, for the input and time in giving your answer.
ToreyHeinz
No problem. You never know when the solution to someone else's problem is going to help you out.
EmFi
A: 

I have realized that the way I want to represent my resources simply falls outside of the normal Rails resources, and that's ok. The problem I was really having was that each time added anther action and named route to get to what I wanted it felt wrong, I was repeating myself, both in my routes and in my actions.

I went back to simply creating my named routes, and spent a little more time in the controller so that I could keep my routes simple. Below is what I have now, and I am ok with it.

#routes.rb
map.with_options :controller => 'sketched_images', :action => 'show', :path_prefix => '/sketches', :name_prefix => 'sketched_', :color => 'grey' do |m|
  m.style "styles/:style/:color/:size.:format"
  m.design "designs/:design/:color/:size.:format"
  m.product "products/:product/:color/:size.:format"
  m.color_combo "colored_products/:color_combo/:size.:format"
end

class SketchedImagesController < ApplicationController
caches_page :show

before_filter :load_data
def show
  @size = params[:size] || 100
  respond_to do |wants|
    wants.png
    wants.jpg
  end
end

private

def load_data
  case 
  when params[:design]
    @image = ClothingDesign.from_param(params[:design]).sketched_image
    greyed
  when params[:style]
    @image = ClothingStyle.from_param(params[:style]).sketched_image
    greyed
  when params[:product]
    @image = Product.from_param(params[:product]).sketched_images.first
    greyed
  when params[:color_combo]
    @color_combo = ColorCombo.find_by_id(params[:color_combo])
    @object = @color_combo.colorable
    if @object.active? && [email protected]_images.blank?
      @image = @object.sketched_images.first
      colored
    else
      @image = @product.style.sketched_image
      dimmed
    end
  end
end

def greyed
  @blank = "#FFF"
  @print = "#000"
  @highlight = "#666"
end

def colored
  @blank = "##{@color_combo.blank_color.value}"
  @print = "##{@color_combo.design_color.value}"
  @highlight = "##{@color_combo.highlight_color.value}" unless @color_combo.highlight_color.blank?
end

def dimmed
  @blank = "#BBB"
  @print = "#000"
  @highlight = "#444"
end

end
ToreyHeinz