Tuesday, August 4, 2009

Match Everything

‹prev | My Chain | next›

There are two related problems to note when searching for an empty string:



The first is that the recipes link (in the categories at the top of the page) is not a link. It should link to all recipes. The second problem is that a search for an empty string ought to return all results.

The first problem is quite easy—a link to /recipes/search?q= works nicely.

The second problem is a little more difficult to solve. The basic strategy is that, given an empty search string, to search for something that matches all documents instead. For my recipes, searching for a couchdb-lucene string of type:Recipe will match, er... all recipes.

Or, in RSpec format:
    it "should search for all doc of type recipe when given an empty string" do
RestClient.should_receive(:get).
with(/q=type:Recipe/).
and_return('{"total_rows":1,"skip":0,"limit":20,"rows":[]}')

get "/recipes/search?q="
end
I define a constant for the default search and use it when the query is empty:
DEFAULT_QUERY = "type:Recipe"
...
get '/recipes/search' do
@query = params[:q] == '' ? DEFAULT_QUERY : params[:q]
...
If returning all recipes, then a default sort order is a must. Sorting by date makes the most sense:
    it "should sort by date when given an empty string" do
RestClient.should_receive(:get).
with(/sort_date/).
and_return('{"total_rows":1,"skip":0,"limit":20,"rows":[]}')

get "/recipes/search?q="
end
Getting this to pass is relatively easy:
get '/recipes/search' do
@query = params[:q] == '' ? DEFAULT_QUERY : params[:q]
@sort = params[:q] == '' ? "%5Csort_date" : params[:sort]
...
Yup, easy enough! Checking in the browser, however, I find:



The search and the sort are working, but the non-user friendly search term, type:Recipe is being displayed in the refine-your-search text field. An example describing that the text field should be empty might look like:
  it "should display an empty search when searching for all recipes" do
assigns[:query] = "type:Recipe"
render("/views/_search_form.haml")
response.should have_selector("input", :name => "q", :value => "")
end
That example fails with the following:
1)
'_search_form.haml should display an empty search when searching for all recipes' FAILED
expected following output to contain a <input value='' name='q'/> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><form action="/recipes/search" id="search-form" method="get">
<input maxlength="2048" name="q" size="31" type="text" value="type:Recipe"><input name="s" type="submit" value="Search">
</form></body></html>
./spec/views/_search_form.haml_spec.rb:15:
As expected the query term is still included in the text field. To ensure that it is not included (and to get the example passing), all that is required is a simple substitution:
  %input{:type      => "text",
:value => @query.to_s.sub(%r{#{DEFAULT_QUERY}}, ''),
:name => "q",
...
After verifying in the browser that an empty refine-your-search field is now shown, I notice something that you tend to only notice when playing with really large datasets:



D'oh! I have to clean up the pagination a bit. Tomorrow.

No comments:

Post a Comment