views:

100

answers:

1

Take a look at haystack

If you click on $3,000 and under take a look at the url it will be:

"3000-under"

Assuming you're using Search Logic how would this be done in the routes?

For quick reference by default search logic suggests search[:params] which maps to a model field. For instance, Haystack's case: {:search => {:price_less_than => '3000'}}

What also stumps me is how they can scope it to any city like /los-angeles/3000-under but once I see the routes it may make more sense.

Next question, what's the best way to handle the way they present which route is currently active?

For instance if you click "Any Budget" and redirect, it'll say "Any Budget" there, and if you click "3000 and under" it'll redirect and then say "3000 and under" there. I'm assuming they are matching against the url and displaying appropriate text inline with that?

+1  A: 

Can't be sure without seeing the routes/controllers, but it looks like some default routing abuse.

You might notice just typing in a url that isn't hinted at in that budget drop down doesn't actually narrow down the results. I don't think it's using any complicated search logic, my guess is it's just named scopes.

Routes:

map.connect ':location/:terms', :controller => "companies", :action => "for_location"
map.connect ':terms', :controller => "companies", :action => "for_budget"

Then the companies controller is probably set up something like this:

def for_location
  @location = Location.find_by_name(params[:location])
  @companies = case params[:terms]
  when /3000-under|3000-to-10000|10000-to-25000|25000-to-50000|50000-above/
    @location.companies.send(params[:terms])
  else 
    @location.companies
  end
end

def for_budget
  @companies = case params[:terms]
  when /3000-under|3000-to-10000|10000-to-25000|25000-to-50000|50000-above/
    Companies.send(params[:terms])
  else 
    @companies = Companies.all
  end
end

Named scopes are defined as:

class Company < ActiveRecord::Base
  ...
  named_scope :3000-under, :conditions => "budget <= 3000"
  named_scope :3000-to-10000, :conditions => "budget >= 3000 AND budget <= 10000"
  named_scope :3000-to-10000, :conditions => "budget >= 10000 AND budget <= 25000"
  named_scope :3000-to-10000, :conditions => "budget >= 25000 AND budget <= 50000"
  named_scope :3000-to-10000, :conditions => "budget >= 50000"
end

EDIT: Because making this dynamic is an interesting problem...

You can make the whole search dynamic with only a tiny bit more effort.

Routes:

map.connect ':location/:term1-:term2', :controller => "companies",
   :action => "for_location", :term1 => /\d+|under|above/, :term2 => /\d+/
map.connect ':term1-:term2', :controller => "companies", :action => "for_budget", 
   :term1 => /\d+|under|above/, :term2 => /\d+/

controller:

def for_location
  @location = Location.find_by_name(params[:location])
  @companies = @location.companies.send("search_#{params[:term1]}_#{params[:term2]}")
end

def for_budget
  @companies = Companies.send("search_#{params[:term1]}_#{params[:term2]}")
end

model:

def self.method_missing(method, *args)
  if method.match(/^search_(under|above|\d+)_(\d+)$/)
     first_term, second_term = $1, $2
     if first_term == "under"
       self.find(:conditions => ["price <= ? ", second_term])
     elsif first_term == "above"
       self.find(:conditions => ["price >= ? ", second_term])
     else
       self.find(:conditions => ["price >= ? AND price <= ?", 
         *[first_term,second_term].sort])
     end
  else
   super(method, *args)
  end
end

Now any route that matches the battern of /:location/300-400 or /:location/under-5000 or /above-27 will use the dynamic finder.

Super Double Bonus: These dynamic searches can be chained with associations and named scopes.

EmFi
DFischer
Although that's not what you asked for in the original question. I've updated the answer to do just that.
EmFi