views:

709

answers:

2

I have a problem where I need values passed in from a GET request and I don't know how to set up the routing definition.

My Category object has a type(string),a color(string) and many products. I want to create a simple web service that lets the caller get all of a Category's products by passing in the Category's type and color:

http://www.myapp.com/getProducts?catType=toy&color=red

or ?

http://www.myapp.com/categories/getProducts?catType=toy&color=red

How do I define the correct routing for this situation? Are there better ways to do this in a Restful manner... because I know that Rails is Restful, so if there is a way to do it "correctly" then that would be even better.

Thanks

+1  A: 

One RESTful way to to do this would involve a product resource nested beneath a category resource, like so:

http://www.myapp.com/categories/toy/products?color=red

Your routes.rb would need to contain:

  map.resources :categories do |category|
    category.resources :products
  end

Since my url above using the Category's type attribute for routing, I'm implying that each type is unique, like an id. It'll mean that whenever you're loading a category in the Categories controller (or anywhere else) you'll need to load the category with Category.find_by_type(params[:id]) instead of Category.find(params[:id]). I like routing categories this way whenever possible.

Your ProductsController controller index action would find products using lines like:

  @category = Category.find_by_type(params[:category_id])
  @products = @category.products.find(:all, :conditions => { :color => params[:color]} ) 

Remember, your Category model must contain the line:

has_many :products

It's probable a good idea to enforce that in the model with validations:

validates_presence_of :type
validates_uniqueness_of :type

To make routing work you should also overwrite the to_param method in the Category model to return type instead of id:

def to_param
  self.type
end
chrisdinn
this wasn't exactly what I was looking for... but I still gave you an up vote because your post was helpful and informative.
Ryan Ferretti
+2  A: 

Your first example:

map.getproduct '/getProduct', :controller => 'your_controller', :action => 'your_action'

In controller you will have catType and color in params hash:

params[:catType]
=> 'toy'
params[:color]
=> 'red'

Is there better way? Probably yes, but it depends on your needs. If you will always have catType and color parameters, than you can add route like this:

map.getproduct '/getProduct/:catType/:color', :controller => 'your_controller', :action => 'your_action'

You will have access to those parameters with params hash like in previous example. And your urls will look like this:

www.myapp.com/getProduct/toy/red

If your parameters may change, you can use route globbing:

    map.getproduct '/getProduct/*query', :controller => 'your_controller', :action => 'your_action'

Then it will catch all request that has www.my.app.com/getProduct/... at the begining. But you will have more work in controller. You will have access to query with this:

 params[:query]

and for www.myapp.com/getProduct/color/red/catType/toy it will give:

 params[:query]
 => ['color', 'red', 'catType', 'toy]

So you have to parse it manualy.

klew
Great... the Restful method was exactly what I wanted! Check and up-vote.
Ryan Ferretti
I don't thing it is Restful. Those routes only search for some collection of products. @chrisdinn answer is more Restful, but I think that searching routes doesn't need to be restful. Restful is mainly for getting colleciton of objects and for manipulation of one of those objects. But anyway I'm happy that my answer was helpful!
klew