Task C: Catalog Display
8.1 Iteration C1: Creating the Catalog Listing
We’ve already created the products controller, used by the seller to administer the Depot application. Now it’s time to create a second controller, one that interacts with the paying customers. Let’s call itStore.
depot> rails generate controller store index create app/controllers/store_controller.rb
route get "store/index"
invoke erb
create app/views/store
create app/views/store/index.html.erb
Prepared exclusively for Jared Rosoff
ITERATIONC1: CREATING THECATALOGLISTING 118
invoke test_unit
create test/functional/store_controller_test.rb invoke helper
create app/helpers/store_helper.rb invoke test_unit
create test/unit/helpers/store_helper_test.rb
Just as in the previous chapter, where we used the generateutility to create a controller and associated scaffolding to administer the products, here we’ve asked it to create a controller (class StoreControllerin the filestore_controller.rb) containing a single action method,index.
While everything is already set up for this action to be accessed via http://
localhost:3000/store/index (feel free to try it!), we can do better. Let’s simplify things for the user and make this the root URL for the web site. We do this by editingconfig/routes.rb:
Download depot_d/config/routes.rb
Depot::Application.routes.draw do get "store/index"
resources :products
# ...
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
# root :to => "welcome#index"
root :to => 'store#index' , :as => 'store'
# ...
end
At the top of the file, you can see the lines added to support the Store and Prod-ucts controller. We’ll leave those lines alone. Further along in the file you will see a commented out line that defines a root for the website. Either uncom-ment out that line, or add a new line immediately after that one. All we are changing on that line is the name of the controller (fromwelcometostore), and adding:as => store. The latter tells rails to create astore_pathvariable, just like thesay_goodbye_paththat we saw on on page52.
Note that the comments also instruct you to deletepublic/index.html. Let’s do that now:1
depot> rm public/index.html
Let’s try it. Point a browser athttp://localhost:3000/and up pops our web page:
1. Windows users will want to executeerase public\index.html
ITERATIONC1: CREATING THECATALOGLISTING 119
It might not make us rich, but at least we know everything is wired together correctly. The page even tells us where to find the template file that draws this page.
Let’s start by displaying a simple list of all the products in our database. We know that eventually we’ll have to be more sophisticated, breaking them into categories, but this will get us going.
We need to get the list of products out of the database and make it available to the code in the view that will display the table. This means we have to change theindex method instore_controller.rb. We want to program at a decent level of abstraction, so let’s just assume we can ask the model for a list of the products we can sell:
Download depot_d/app/controllers/store_controller.rb
class StoreController < ApplicationController def index
@products = Product.all end
end
We ask our customer whether she had a preference regarding the order things should be listed, and we jointly decided to see what happened if we displayed the products in alphabetical order. We do this by adding a default_scope call to the Product model. Default scopes apply to all queries that start with this model.
Download depot_d/app/models/product.rb
class Product < ActiveRecord::Base default_scope :order => 'title'
# validation stuff...
end
Report erratum this copy is (B8.0 printing, September 9, 2010)
Prepared exclusively for Jared Rosoff
ITERATIONC2: ADDING APAGELAYOUT 120
Now we need to write our view template. To do this, edit the fileindex.html.erb inapp/views/store. (Remember that the path name to the view is built from the name of the controller (store) and the name of the action (index). The .html.erb part signifies an ERb template that produces an HTML result.)
Download depot_d/app/views/store/index.html.erb
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
<h1>Your Pragmatic Catalog</h1>
<% @products.each do |product| %>
<div class="entry">
Note the use of thesanitize method for the description. This allows us to safely add HTML stylings to make the descriptions more interesting for our cus-tomers. (Note: this decision opens a potential security hole, but because prod-uct descriptions are created by people who work for our company, we think that the risk is minimal. See Section 21.1, Escaping Substituted Values, on page365for details.
We’ve also used theimage_taghelper method. This generates an HTML<img>
tag using its argument as the image source.
Hitting Refresh brings up the display shown on Figure8.1, on the next page.
It’s pretty ugly, because we haven’t yet included the CSS stylesheet. The cus-tomer happens to be walking by as we ponder this, and she points out that she’d also like to see a decent-looking title and sidebar on public-facing pages.
At this point in the real world, we’d probably want to call in the design folks—
we’ve all seen too many programmer-designed websites to feel comfortable inflicting another on the world. But Pragmatic Web Designer is off getting inspiration on a beach somewhere and won’t be back until later in the year, so let’s put a placeholder in for now. It’s time for another iteration.