Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Agile Web Development With Rails, 2nd Edition (2006).pdf
Скачиваний:
30
Добавлен:
17.08.2013
Размер:
6.23 Mб
Скачать

ITERATION C4: FINISHING THE CAR T 118

David Says. . .

How Much Inline Error Handling Is Needed?

The add_to_cart method shows the deluxe version of error handling in Rails where the particular error is given exclusive attention and code. Not every conceivable error is worth spending that much time catching. Lots of input errors that will cause the application to raise an exception occur so rarely that we’d rather just treat them to a uniform catchall error page.

We talk about setting up a global error handler on page 627.

the application. She notices a minor problem on our new cart display—there’s no way to empty items out of a cart. This minor change will be our next iteration. We should make it before heading home.

8.5Iteration C4: Finishing the Cart

We know by now that in order to implement the empty cart function, we have to add a link to the cart and implement an empty_cart method in the store controller. Let’s start with the template. Rather than use a hyperlink, let’s use the button_to method to put a button on the page.

Download depot_h/app/views/store/add_to_cart.rhtml

<h1>Your Pragmatic Cart</h1>

<ul>

<% for cart_item in @cart.items %>

<li><%= cart_item.quantity %> × <%= h(cart_item.title) %></li> <% end %>

</ul>

<%= button_to "Empty cart", :action => :empty_cart %>

In the controller, we’ll implement the from the session and sets a message index page.

empty_cart method. It removes the cart into the flash before redirecting to the

Download depot_h/app/controllers/store_controller.rb

def empty_cart session[:cart] = nil

flash[:notice] = "Your cart is currently empty" redirect_to :action => :index

end

Report erratum

ITERATION C4: FINISHING THE CAR T 119

Now when we view our cart and click the Empty cart link, we get taken back to the catalog page, and a nice little message says

However, before we break an arm trying to pat ourselves on the back, let’s look back at our code. We’ve just introduced some duplication.

In the store controller, we now have two places that put a message into the flash and redirect to the index page. Sounds like we should extract that common code into a method, so let’s implement redirect_to_index and change the add_to_cart and empty_cart methods to use it.

Download depot_i/app/controllers/store_controller.rb

def add_to_cart begin

product = Product.find(params[:id]) rescue ActiveRecord::RecordNotFound

logger.error("Attempt to access invalid product #{params[:id]}") redirect_to_index("Invalid product")

else

@cart = find_cart @cart.add_product(product)

end end

def empty_cart session[:cart] = nil

redirect_to_index("Your cart is currently empty") end

private

def redirect_to_index(msg) flash[:notice] = msg redirect_to :action => :index

end

And, finally, we’ll get around to tidying up the cart display. Rather than use <li> elements for each item, let’s use a table. Again, we’ll rely on CSS to do the styling.

Download depot_i/app/views/store/add_to_cart.rhtml

<div class="cart-title">Your Cart</div> <table>

<% for cart_item in @cart.items %>

Report erratum

ITERATION C4: FINISHING THE CAR T

120

<tr>

<td><%= cart_item.quantity %>×</td> <td><%= h(cart_item.title) %></td>

<td class="item-price"><%= number_to_currency(cart_item.price) %></td> </tr>

<% end %>

<tr class="total-line" >

<td colspan="2">Total</td>

<td class="total-cell"><%= number_to_currency(@cart.total_price) %></td> </tr>

</table>

<%= button_to "Empty cart", :action => :empty_cart %>

To make this work, we need to add a method to the Cart model that returns the total price of all the items. We can implement one using Rails’ nifty sum method to sum the prices of each item in the collection.

Download depot_i/app/models/cart.rb

def total_price

@items.sum { |item| item.price } end

This gives us a nicer-looking cart.

What We Just Did

It has been a busy, productive day. We’ve added a shopping cart to our store, and along the way we’ve dipped our toes into some neat Rails features.

Using sessions to store state

Creating and integrating nondatabase models

Using the flash to pass errors between actions

Using the logger to log events

Removing duplication from controllers

Report erratum

ITERATION C4: FINISHING THE CAR T 121

We’ve also generated our fair share of errors and seen how to get around them.

But, just as we think we’ve wrapped this functionality up, our customer wanders over with a copy of Information Technology and Golf Weekly. Apparently, there’s an article about a new style of browser interface, where stuff gets updated on the fly. “AJAX,” she says, proudly. Hmmm...let’s look at that tomorrow.

Playtime

Here’s some stuff to try on your own.

Add a new variable to the session to record how many times the user has accessed the index action. (The first time through, your count won’t be in the session. You can test for this with code like

if session[:counter].nil?

...

If the session variable isn’t there, you’ll need to initialize it. Then you’ll be able to increment it.

Pass this counter to your template, and display it at the top of the catalog page. Hint: the pluralize helper (described on page 474) might be useful when forming the message you display.

Reset the counter to zero whenever the user adds something to the cart.

Change the template to display the counter only if it is greater than five.

(You’ll find hints at http://wiki.pragprog.com/cgi-bin/wiki.cgi/RailsPlayTime)

Report erratum