- •Introduction
- •Rails Is Agile
- •Finding Your Way Around
- •Acknowledgments
- •Getting Started
- •Models, Views, and Controllers
- •Installing Rails
- •Installing on Windows
- •Installing on Mac OS X
- •Installing on Unix/Linux
- •Rails and Databases
- •Keeping Up-to-Date
- •Rails and ISPs
- •Creating a New Application
- •Hello, Rails!
- •Linking Pages Together
- •What We Just Did
- •Building an Application
- •The Depot Application
- •Incremental Development
- •What Depot Does
- •Task A: Product Maintenance
- •Iteration A1: Get Something Running
- •Iteration A2: Add a Missing Column
- •Iteration A4: Prettier Listings
- •Task B: Catalog Display
- •Iteration B1: Create the Catalog Listing
- •Iteration B2: Add Page Decorations
- •Task C: Cart Creation
- •Sessions
- •More Tables, More Models
- •Iteration C1: Creating a Cart
- •Iteration C3: Finishing the Cart
- •Task D: Checkout!
- •Iteration D2: Show Cart Contents on Checkout
- •Task E: Shipping
- •Iteration E1: Basic Shipping
- •Task F: Administrivia
- •Iteration F1: Adding Users
- •Iteration F2: Logging In
- •Iteration F3: Limiting Access
- •Finishing Up
- •More Icing on the Cake
- •Task T: Testing
- •Tests Baked Right In
- •Testing Models
- •Testing Controllers
- •Using Mock Objects
- •Test-Driven Development
- •Running Tests with Rake
- •Performance Testing
- •The Rails Framework
- •Rails in Depth
- •Directory Structure
- •Naming Conventions
- •Active Support
- •Logging in Rails
- •Debugging Hints
- •Active Record Basics
- •Tables and Classes
- •Primary Keys and IDs
- •Connecting to the Database
- •Relationships between Tables
- •Transactions
- •More Active Record
- •Acts As
- •Aggregation
- •Single Table Inheritance
- •Validation
- •Callbacks
- •Advanced Attributes
- •Miscellany
- •Action Controller and Rails
- •Context and Dependencies
- •The Basics
- •Routing Requests
- •Action Methods
- •Caching, Part One
- •The Problem with GET Requests
- •Action View
- •Templates
- •Builder templates
- •RHTML Templates
- •Helpers
- •Formatting Helpers
- •Linking to Other Pages and Resources
- •Pagination
- •Form Helpers
- •Layouts and Components
- •Adding New Templating Systems
- •Introducing AJAX
- •The Rails Way
- •Advanced Techniques
- •Action Mailer
- •Sending E-mail
- •Receiving E-mail
- •Testing E-mail
- •Web Services on Rails
- •Dispatching Modes
- •Using Alternate Dispatching
- •Method Invocation Interception
- •Testing Web Services
- •Protocol Clients
- •Securing Your Rails Application
- •SQL Injection
- •Cross-Site Scripting (CSS/XSS)
- •Avoid Session Fixation Attacks
- •Creating Records Directly from Form Parameters
- •Knowing That It Works
- •Deployment and Scaling
- •Picking a Production Platform
- •A Trinity of Environments
- •Iterating in the Wild
- •Maintenance
- •Finding and Dealing with Bottlenecks
- •Case Studies: Rails Running Daily
- •Appendices
- •Introduction to Ruby
- •Ruby Names
- •Regular Expressions
- •Source Code
- •Cross-Reference of Code Samples
- •Resources
- •Index
|
|
|
|
|
I TERATION D2: SHOW CAR T CONTENTS ON CHECKOUT |
104 |
|||
depot> mysql depot_development |
|
|
|
|
|
||||
Welcome to the MySQL monitor. Commands end with ; or \g. |
|
|
|
||||||
mysql> select * from orders; |
|
|
|
|
|
||||
+ |
----+ |
------------- |
+----------------------- |
|
+ |
------------- |
+---------- |
+ |
|
| id | |
name |
|
| address |
| pay_type | |
|
||||
+---- |
+------------- |
|
+----------------------- |
|
+------------- |
|
+---------- |
+ |
|
| |
3 | |
Dave Thomas | customer@pragprog.com | 123 Main St | check |
| |
|
|||||
+---- |
+------------- |
|
+----------------------- |
|
+------------- |
|
+---------- |
+ |
|
1 |
row in set (0.00 sec) |
|
|
|
|
|
|
||
mysql> select * from line_items; |
|
|
|
|
|||||
+---- |
+------------ |
|
+---------- |
+ |
----------+------------ |
+ |
|
|
|
| id | |
product _ id | order_id | quantity | unit_price | |
|
|
|
|||||
+---- |
+------------ |
|
+---------- |
+---------- |
+------------ |
+ |
|
|
|
| |
4 | |
|
4 | |
3 | |
1 | |
29.95 | |
|
|
|
+---- |
+------------ |
|
+---------- |
+---------- |
+------------ |
+ |
|
|
|
1 |
row in set (0.00 sec) |
|
|
|
|
|
|
Ship it! Or, at least, let’s show it to our customer. She likes it. Except....
Do you suppose we could add a summary of the cart contents to the checkout page? Sounds like we need a new iteration.
|
9.2 Iteration D2: Show Cart Contents on Checkout |
|
In this iteration we’re going to add a summary of the cart contents to the |
|
checkout page. This is pretty easy. We already have a layout that shows |
|
the items in a cart. All we have to do is cut and paste the code across |
|
into the checkout view and...ummm...oh, yeah, you’re watching what I’m |
|
doing. |
|
OK, so cut-and-paste coding is out, because we don’t want to add dupli- |
|
cation to our code. What else can we do? It turns out that we can use |
|
Rails components to allow us to write the cart display code just once and |
|
invoke it from two places. (This is actually a very simple use of the compo- |
|
nent functionality; we’ll see it in more detail in Section 17.9, Layouts and |
|
Components, on page 356.) |
|
As a first pass, let’s edit the view code in checkout.rhtml to include a call to |
|
render the cart at the top of the page, before the form. |
File 38 |
<%= error_messages_for("order") %> |
|
<%= render_component(:action => "display_cart") %> |
|
<%= start_form_tag(:action => "save_order") %> |
|
<table> |
|
<tr> |
|
<td>Name:</td> |
|
The render_component( ) method invokes the given action and substitutes |
|
the output it renders into the current view. What happens when we run |
|
this code? Have a look at Figure 9.4, on page 106. |
Prepared exclusively for Rida Al Barazi
Report erratum
ITERATION D2: SHOW CAR T CONTENTS ON CHECKOUT |
105 |
Figure 9.3: Our First Checkout
Prepared exclusively for Rida Al Barazi
Report erratum
ITERATION D2: SHOW CAR T CONTENTS ON CHECKOUT |
106 |
Figure 9.4: Methinks The Component Renders Too Much
|
Oops! Invoking the display_cart action has substituted in the entire ren- |
|
dered page, including the layout. While this is interesting in a post- |
|
modern, self-referential kind of way, it’s probably not what our buyers |
|
were expecting to see. |
|
We’ll need to tell the controller not to use our fancy layout when it’s ren- |
|
dering the cart as a component. Fortunately, that’s not too difficult. We |
|
can set parameters in the render_component( ) call that are accessible in |
|
the action that’s invoked. We can use a parameter to tell our display_cart( ) |
|
action not to invoke the full layout when it’s being invoked as a compo- |
|
nent. It can override Rails’ default rendering in that case. The first step is |
|
to add a parameter to the render_component( ) call. |
File 40 |
<%= render_component(:action => "display_cart", |
|
:params => { :context => :checkout }) %> |
|
We’ll alter the display_cart( ) method in the controller to call different render |
|
methods depending on whether this parameter is set. Previously we didn’t |
|
have to render our layout explicitly; if an action method exits without |
|
calling a render method, Rails will call render( ) automatically. Now we |
|
need to override this, calling render(:layout=>false) in a checkout context. |
Prepared exclusively for Rida Al Barazi
Report erratum
ITERATION D2: SHOW CAR T CONTENTS ON CHECKOUT |
107 |
File 39 |
def display_cart |
|
@cart = find_cart |
|
@items = @cart.items |
|
if @items.empty? |
|
redirect_to_index("Your cart is currently empty") |
|
end |
if params[:context] == :checkout render(:layout => false)
end end
When we hit Refresh in the browser, we see a much better result.
We call our customer over, and she’s delighted. One small request: can we remove the Empty cart and Checkout options from the menu at the right? At the risk of getting thrown out of the programmers union, we say, “That’s not a problem.” After all, we just have to add some conditional code to the display_cart.rhtml view.
File 42 |
<ul> |
|
|
<li><%= link_to 'Continue shopping', :action => "index" %></li> |
|
|
<% unless params[:context] == :checkout -%> |
|
|
<li><%= link_to 'Empty cart', |
:action => "empty_cart" %></li> |
|
<li><%= link_to 'Checkout', |
:action => "checkout" %></li> |
|
<% end -%> |
|
|
</ul> |
|
|
While we’re at it, we’ll add a nice little heading just before the start of the |
|
form in the template checkout.rhtml in app/views/store. |
File 41 |
<%= error_messages_for("order") %> |
|
<%= render_component(:action => "display_cart", |
|
:params => { :context => :checkout }) %> |
|
<h3>Please enter your details below</h3> |
Prepared exclusively for Rida Al Barazi
Report erratum
ITERATION D2: SHOW CAR T CONTENTS ON CHECKOUT |
108 |
A quick refresh in the browser, and we have a nice looking checkout page.
Our customer is happy, our code is neatly tucked into our repository, and it’s time to move on. Next we’ll be looking at adding shipping functionality to Depot.
What We Just Did
In a fairly short amount of time, we did the following.
•Added an orders table (with corresponding model) and linked its rows to the line items we’d defined previously
•Created a form to capture details for the order and linked it to the
Order model
•Added validation and used helper methods to display errors back to the user
•Used the component system to include the cart summary on the checkout page
Prepared exclusively for Rida Al Barazi
Report erratum