Adding a Search Facility

The first step in extending the system is to enable searching for people. This requires changes to a few parts of the system:

  • A new action, which performs the search against the Person model, retrieving an array of Person instances from the database. As the search only uses the Person model, the logical place to locate the action is in the controller, which manages the other actions for that model: PeopleController. We'll call the action search.
  • A view template to display the results of the search. We already have a view template that can render an array of Person instances: app/views/people/index.rhtml. Therefore, we can just reuse that template, with some minor modifications such as a different page title.
  • A form where a user can type a search term and perform the search. We can add this to the layout for the application (app/layouts/application.rhtml) to make it available from any page.

Once this functionality is in place, we'll be able to search the people table with a URL like this:

http://localhost:3000/people/search?term=James

We first need a search action on the PeopleController (in app/controllers/people_controller.rb). This is fairly similar to the index action: it retrieves a set of records from the database using a paginator and displays them. As noted above, we can also use the same view template (index.rhtml) to output the HTML, but we'll have to explicitly call it inside the action (highlighted below) as the action name doesn't match the template name. Here's the action in full:

def search
@paginator, @people = paginate :person, :per_page => 10,
:select => 'id, last_name, first_name',
:order => 'last_name, first_name'
@page_title = "Search results (page #{@paginator.current.number})"
render :action => 'index'

end

Test this at http://localhost:3000/people/search?term=Jeff (put anything you like at the end of the URL—it's not being used yet). You should see something very similar to the index page for PeopleController, but with a different title (Search results...). This proves that the route, action, and template are all working together.

Next, we need to use the term parameter passed in the URL to narrow the results. In Chapter 4 (Finding Records Matching Search Criteria), we saw how to use a :conditions option to restrict the results returned by find. We can also use a :conditions option with the paginate method to restrict by our search term (highlighted):

def search
# Get the search term from the querystring and put
# percentage signs round it so it can be used with a LIKE query
term = "%#{params[:term]}%"

@paginator, @people = paginate :person, :per_page => 10,
:select => 'id, last_name, first_name',
:order => 'last_name, first_name',
:conditions => ['last_name LIKE :term or first_name LIKE :term 
OR notes LIKE :term OR keywords LIKE :term', {:term => term}]

@page_title = "Search results (page #{@paginator.current.number})"
render :action => 'index'
end

The :conditions option here uses an alternative syntax available for SQL templates: instead of a question mark in the query (as used in Chapter 4, Finding Records Matching Search Criteria), you can use named placeholders, prefixed with a colon character. Then, you can use a hash as the second element of the array (here, {:term => term}) to specify the values to insert into the placeholders. Here we're using a single value, which gets inserted into four places in the query. This is a neat shortcut, particularly when you need to put the same value into multiple places in the query.

Now, try doing a search for someone in your database. For example, if you have a person called "Jeff" in your database, try doing:

http://localhost:3010/people/search?term=jeff

As we used LIKE in the query, the search is case-insensitive (at least, when using MySQL). Hopefully, the page should only show people matching your query, e.g.:

Adding a Search Facility

The last step is to add a search form. To keep things simple, we'll add it to the layout directly (app/views/layouts/application.rhtml), at the bottom of the menu:

<li><%= link_to 'Addresses', :controller => 'addresses' %></li>
</ul>
<p>Search people</p>
<% form_tag({:controller => 'people', :action => 'search'}, {:method => :get}) do -%>
<p><input type="text" name="term" size="8" value=""/><br/>
<%= submit_tag 'Go' %></p>
<% end -%>

</div>

As we haven't got a model instance we are working with here, form_for (which we used in Chapter 5, e.g. in the section Creating a Person) isn't really applicable. The simpler form_tag helper generates an HTML<form> element, which doesn't need to reference a model. It's also possible to pass both URL options (the first argument) and HTML options (the second argument) to the helper, to customize its behavior: in this case, we set the method to GET, to pass the term variable in the querystring.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.34.62