In this conclusion to a three-part series on building an online book catalog application with Ruby-on-Rails, we'll finish creating the search ability and add both a regular page and an RSS feed that lets users see the latest book titles to arrive at the store. This article is excerpted from chapter four of the book Practical Rails Projects, written by Eldon Alameda (Apress; ISBN: 1590597818).
Saving it as a partial makes it possible for us to easily embed the search form in other pages.
In the code, we create a simple form that points to thesearchaction and uses thegetmethod. Usinggetinstead ofpost will make the query string be a part of the URL. That way, Jill can circulate a link to her search results to all of her friends. Our form has only two elements: a text fieldqand the submit button.
In the actual search template, we display the partial using therendermethod. Save the following line toapp/views/catalog/search.rhtml:
def search @page_title = "Search" if params[:commit] == "Search" || params[:q] @books = Book.find_by_contents(params[:q].to_s.upcase) unless @books.size > 0 flash.now[:notice] = "No books found matching your criteria" end end end
In thesearchaction, we first specify the title for the page. Then we continue in two different directions, depending on whether the search form was already submitted or the search page was just requested normally. We do the separation by checking if either the value of a query parametercommit is"Search"or the query variableq is specified. From the_search.rhtmlpartial view,q contains the search text that was submitted by the search form.
If our code determines that the form has been submitted, it executes the search using thefind_by_contentsclass method and the query parameterq. Furthermore, if there are no books found with the terms, it sets the flash notice to show a message to the user.
Modifying the View
Now we need to extend our search view so that it shows either the books found or the “Not found” notice. Add the following toapp/views/catalog/search.rhtml:
<%= render :partial => "search_box" %>
<% if @books %> <p>Your search "<%= params[:q] %>" produced <%= pluralize @books.size, "result" %>:</p> <%= render(:partial => "books") %> <% end %>
If the search was successful, we also tell how many hits there were. We use thepluralize helper to show the number of books, and the word “result” in singular or plural depending on the count. Last, we render a partial to show a list of matching books.
We don’t have a partial view called books yet, so we need to create it. In theindexaction, we also showed a list of books, so it is a good place to extract the list. Move the following code fromapp/views/catalog/index.rhtmltoapp/views/catalog/_books.rhtml.
<dl id="books"> <% for book in @books %> <dt><%= link_to book.title.t, :action => "show", :id => book %></dt> <% for author in book.authors %> <dd><%= author.last_name %>, <%= author.first_name %></dd> <% end %> <dd><%= pluralize(book.page_count, "page") %></dd> <dd>Price: $<%= sprintf("%.2f", book.price) %></dd> <dd><small>Publisher: <%= book.publisher.name %></small></dd> <% end %> </dl>
Now we can just replace the moved code inindex.rhtmlwith a similarrendercall that we have in the end of thesearch.rhtmltemplate, and that’s it! We have a functioning search form in the bookstore.
If you have already added some books to your development system, you can point your browser to/catalog/searchon your development site and see the result for yourself, as shown in Figure 4-3. (First, you will need to restart your web server, so it will pick up the introduced Ferret code.)
Figure 4-3. Search interface
We also need a link to our search functionality, so add the following toapp/views/catalog/index.rhtml: