views:

724

answers:

2

DocumentsController#common_query can handle multiple different request styles.

i.e. all docs in batch 4 or all docs tagged "happy"

I want a single route to make em pretty, so:

/documents/common_query?batch=4

/documents/common_query?tag=happy

become:

/documents/batch/4

/documents/tag/happy

So the end result is that #common_query is called but part of the url was used as the param name and part as it's value.

A: 

As a single route:

ActionController::Routing::Routes.draw do |map|
  map.connect "documents/:type/:id", :controller => "documents_controller", 
              :action => "common_query"
end

Then params[:type] will either be "batch" or "tag", and params[:id] either "4" or "happy". You will have to make sure that other actions for the DocumentsController come before this in the routes because this will match any url that looks like "documents/*/*".

But why does it have to be a single route? You could use two routes like this:

map.with_options(:controller => "documents_controller", 
                 :action => "common_query") do |c|
  c.connect "documents/batch/:page", :type => "batch"
  c.connect "documents/tag/:tag",    :type => "tag"
end

which will have the same effect, but is more specific, so you wouldn't have to worry about the priority order of the routes.

Daniel Lucraft
+1  A: 

The second option, with two routes, is almost certainly the better way to go, because it will only match the kinds of URLs that you want to support, while the first option will also "match" URLs like /documents/foo/bar, which will likely cause your #common_query method to, at best, return a RecordNotFound (404) response. At worst, if you're not ready to not see any of your expected params, you'll get a 500 error instead...

Of course, if you start having a lot of variations, you end up with a lot of routes. And if you need to use them in combination, e.g., /documents/batch/4/tag/happy, then you'll need to use a wildcard route, and do the parameter processing in your controller. This might look something like:

map.connect 'documents/*specs', :controller => "documents_controller", :action => "common_query"

The various elements of the URL will be available your controller as params[:specs]. You might turn that into a find like so:

@items = Item.find(:all, :conditions => Hash[params[:specs]])

That Hash[] technique converts the one dimensional array of options into a key-value hash, which might be useful even if you're not feeding it directly to a find().

Alderete