Agile Web Development with Rails Translator (15)

Source: Internet
Author: User
Tags error handling

Agile Web Development with Rails Translator (15)

Organize your shopping cart

Before we finish this work and show the customer, let's tidy up the shopping cart display page. Instead of simply dumping this product, let's add some formatting. At the same time, we can add some continuous shopping connections so that we don't have to press the back button only. When we add a connection, let's add an empty connection to the cart after payment.

April 17, 2006 Update

Our new display_cart.rhtml file looks like this:

<div id= "Cartmenu" >

<ul>

<li><%= link_to ' Continue shopping ',: action = "Index"%></li>

<li><%= link_to ' Empty cart ',: action = "Empty_cart"%></li>

<li><%= link_to ' Checkout ',: action = "Checkout"%></li>

</ul>

</div>

<table cellpadding= "cellspacing=" 0 ">

<tr class= "Carttitle" >

<TD rowspan= "2" >Qty</td>

<TD rowspan= "2" >Description</td>

<TD colspan= "2" >Price</td>

</tr>

<tr class= "Carttitle" >

<td>Each</td>

<td>Total</td>

</tr>

<%

For item in @items

Product = Item.product

-%>

<tr>

<td><%= item.quantity%></td>

<td><%= h (product.title)%></td>

<TD align= "Right" ><%= item.unit_price%></td>

<TD align= "Right" ><%= Item.unit_price * item.quantity%></td>

</tr>

<% End%>

<tr>

<TD colspan= "3" align= "right" ><strong>Total:</strong></td>

<TD id= "Totalcell" ><%= @cart. Total_price%></td>

</tr>

</table>

After using some CSS magic, our shopping cart looks like Figure 8.3.

I'm glad we did the work, we came to the client and showed him our morning job. He was glad to see that the site was assembled together. She was worried, however, when she read a commercial news about an ongoing e-commerce site that was attacked every day and compromised security. One of the attacks she read was to send a request with incorrect parameters to a Web application in order to expose defects and security vulnerabilities. He notes that adding items to the shopping cart connection looks like this store/add_to_car/nnn, while NNN is our internal product ID. Like maliciously, he entered the request manually to the browser and gave it the ID number of the product "Wibble". When he saw the display of Figure 8.4, he didn't say anything. So the next time, it takes a while for the application to be more resilient.

8.4 loop C2: Handling Errors

Looking at Figure 8.4, it shows that our application throws an exception in line eighth of the store "controller". This is the line:

Product = Product.find (Params[:id])

If the product is not found, the "activity log" throws an Recordnotfound exception that we need to handle. The question is what we should do.

And we can silently ignore it. From a security standpoint, it may be best to remove it, rather than giving any information to potential attackers. However, it also means that we should not have the code to generate the wrong product ID, and our application will not answer the error-no one knows it is a mistake.

Instead, when an exception is thrown, we accept three actions. First, we'll use rails's logging feature to log it to the logs (described on page 186). Next, we will output a short message to tell the user. Finally, we will re-display the catalog page to the user so that it can continue browsing our site.

The flash!

As you can guess, rails has a handy way to handle errors and bug reports. It defines a structure called flash. A flash is a "bucket" (actually more like a hash table) where you can store something you handle a request. The next request for this "session" is valid until the Flash content is automatically deleted. Typically, flash is used to collect error messages. For example, when our Add_to_cart () action detects that it is passed an invalid product ID, it can store that error message in Flash and redirect the index () action to re-display the directory. The view of the index action extracts the error and displays the error at the top of the catalog page. Flash information can be accessed through the @flash instance variable within the view.

Why can't we just store the error into any of the original instance variables? Remember that redirects are sent to the browser by our app, which will send a new request to the app. When we received the request, the app moved on and all the instance variables from the previous request disappeared forever. The flash data is stored in a "session" to make it valid between the two requests.

With flash data to prevent such errors, we can now modify our Add_to_cart () method so that it accepts the wrong product ID and reports the problem.

def Add_to_cart

Product = Product.find (Params[:id])

@cart = Find_cart

@cart. Add_product (product)

Redirect_to (: action = ' Display_cart ')

Rescue

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

Flash[:notice] = ' Invalid product '

Redirect_to (: action = ' index ')

End

The rescue clause intercepts the exception that is thrown by Product.find (). In the handler, we use rails ' logger to record this error, create a flash notification with a description, and redirect back to the catalog display page. (why redirect, rather than displaying the catalog page directly here.) If we redirect, the browser's URL tail is displayed as Http://.../store/index instead of http://.../store/add_to_cart/wibble. We reduce the exposure to the application in this way. We also prevent the user from pinning the error again by pressing the reload button. )

We can then repeat the error entered by the customer. These, when we explicitly enter the following command

Http://localhost:3000/store/add_to_cart/wibble

We don't see heap errors in the browser. Instead, the category catalog page is displayed. If we look at the tail of the log file (the Development.log file in the log directory), we see our message.

Parameters: {"Action" = "Add_to_cart", "id" = "wibble", "Controller" = "Store"}

Product Load (0.000439) SELECT * FROM products WHERE id = ' wibble ' LIMIT 1

Attempt to access invalid product wibble

Redirected to Http://localhost:3000/store/

: : :

Rendering Store/index within Layouts/store

Rendering Layouts/store ($ OK)

Completed in 0.006420 (155 reqs/sec) | rendering:0.003720

(57%) | db:0.001650 (25%)

The log starts working, but the flash message does not appear on the user's browser. That's because we didn't show it. We will show adding something to the "layer" to tell it if they exit the flash message to be displayed. The following rhtml code checks the notification level of the Flash message, if necessary, and creates a new <div> contains it.

<% if @flash [: notice]-%>

<div id= "notice" ><%= @flash [: notice]%></div>

<% End-%>

So where do we put the code? We can put the category in the top of the "template" display-within the index.rhtml code. After all, we think there is the right place. However, when we continue to develop, we will feel that there is a standard error display is the best way. We've used the "layers" of rails to get a consistent look for all the store pages, so let's add a flash processing code to that "layer". If our client suddenly decides that the error will look better in the tool bar, then we can just change one place and all of our stored pages will be updated. So our new store "layer" code looks like this.

<title>pragprog Books Online store</title>

<%= Stylesheet_link_tag "Depot",: Media = "All"%>

<body>

<div id= "banner" >

<%= @page_title | | "Pragmatic Bookshelf"%>

</div>

<div id= "Columns" >

<div id= "Side" >

<a href= "http://www ..." >home</a><br/>

<a href= "Http://www..../faq" >questions</a><br/>

<a href= "Http://www..../news" >news</a><br/>

<a href= "Http://www..../contact" >contact</a><br/>

</div>

<div id= "Main" >

<% if @flash [: notice]-%>

<div id= "notice" ><%= @flash [: notice]%></div>

<% End-%>

<%= @content_for_layout%>

</div>

</div>

</body>

This time, when we manually entered an invalid product ID, we saw an error report at the top of the catalog page.

When we look in this way, a malicious user will mess up our application, and we notice that when the shopping cart is empty, the Display_cart () "Action" will be called directly from the browser. It's not a big problem-it just shows an empty list and a total of zeros, but we should do better than that. We can use our flash feature to do redirection when displaying a good hint to the user trying to use an empty shopping cart. We will modify the Display_cart () method in the store "controller".

def Display_cart

@cart = Find_cart

@items = @cart. Items

If @items. Empty?

Flash[:notice] = "Your cart is currently empty"

Redirect_to (: action = ' index ')

End

End

-----------------------------------------------------------------

David said ...

how many built-in error handlers are required.

The Add_to_cart () method shows a high-level version of error handling within rails, where specific errors are given enough attention and code. It's impossible to spend time thinking about catching all the mistakes. Many input errors will cause an application-induced abortion exception. So we seldom do this, we just treat the exception as a unified catchall error page. Such an error page can be implemented within Applicationcontroller, where the Rescue_action_in_public (exception) method is called when an exception occurs but is not captured by the lower layer. More information on this technique is in the 22nd chapter of page 440.

------------------------------------------------------------------

Remember that we set the store "layer" on page 71 using the value of @page_title (if defined). Let's use this feature now. Edit the template display_cart.rhtml to overwrite the page title, regardless of whether it is used or not. This is a good feature: the instance variables set in the template are valid in the layer.

<% @page_title = "Your pragmatic Cart"-%>

At the end of the feeling, we came to the customer and showed that we have now properly handled the error. He was satisfied and went on experimenting with our application. He noticed two points on our new shopping cart Display page. First, the empty shopping cart button should not be connected to anything. Second, if you add the same book two times to the shopping cart, it shows that the total amount is 59.9 instead of $59.90. These two minor changes are done at the next modification.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.