Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails Routing with Query String

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

like image 554
Ryan Ferretti Avatar asked Feb 13 '10 14:02

Ryan Ferretti


2 Answers

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.

like image 184
klew Avatar answered Sep 21 '22 12:09

klew


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
like image 23
chrisdinn Avatar answered Sep 21 '22 12:09

chrisdinn