The Depot Application

The Depot Application

13 Task I: Internationalization 11.4 Iteration F4: Adding a Sidebar, More Administration

12.1 Generating the XML Feed

edit app/models/product.rb
class Product < ActiveRecord::Base
  has_many :orders, :through => :line_items
  has_many :line_items
  # ...
rails generate controller info who_bought
      create  app/controllers/info_controller.rb
       route  get "info/who_bought"
      invoke  erb
      create    app/views/info
      create    app/views/info/who_bought.html.erb
      invoke  test_unit
      create    test/functional/info_controller_test.rb
      invoke  helper
      create    app/helpers/info_helper.rb
      invoke    test_unit
      create      test/unit/helpers/info_helper_test.rb
edit app/controllers/info_controller.rb
class InfoController < ApplicationController
  def who_bought
    @product = Product.find(params[:id])
    @orders  = @product.orders
    respond_to do |format|
      format.xml { render :layout => false }
    end
  end
 
protected
 
  def authorize
  end
end
edit app/views/info/who_bought.xml.builder
xml.order_list(:for_product => @product.title) do
  for o in @orders
    xml.order do
      xml.name(o.name)
      xml.email(o.email)
    end
  end
end
curl --silent http://localhost:3000/info/who_bought/3
<order_list for_product="Pragmatic Version Control">
  <order>
    <name>Dave Thomas</name>
    <email>customer@example.com</email>
  </order>
</order_list>
curl --silent http://localhost:3000/info/who_bought/3
<order_list for_product="Pragmatic Version Control">
  <order>
    <name>Dave Thomas</name>
    <email>customer@example.com</email>
  </order>
</order_list>
sqlite3> select * from products
         id = 2
      title = Pragmatic Project Automation
description = <p>
       <em>Pragmatic Project Automation</em> shows you how to improve the 
       consistency and repeatability of your project's procedures using 
       automation to reduce risk and errors.
      </p>
      <p>
        Simply put, we're going to put this thing called a computer to work 
        for you doing the mundane (but important) project stuff. That means 
        you'll have more time and energy to do the really 
        exciting---and difficult---stuff, like writing quality code.
      </p>
  image_url = /images/auto.jpg
 created_at = 2010-08-07 13:14:15.562819
 updated_at = 2010-08-07 13:14:15.562819
      price = 29.95
 
         id = 3
      title = Pragmatic Version Control
description = <p>
         This book is a recipe-based approach to using Subversion that will 
         get you up and running quickly---and correctly. All projects need
         version control: it's a foundational piece of any project's 
         infrastructure. Yet half of all project teams in the U.S. don't use
         any version control at all. Many others don't use it well, and end 
         up experiencing time-consuming problems.
      </p>
  image_url = /images/svn.jpg
 created_at = 2010-08-07 13:14:15.567893
 updated_at = 2010-08-07 13:14:15.567893
      price = 28.5
 
         id = 4
      title = Pragmatic Unit Testing (C#)
description = <p>
        Pragmatic programmers use feedback to drive their development and 
        personal processes. The most valuable feedback you can get while 
        coding comes from unit testing.
      </p>
      <p>
        Without good tests in place, coding can become a frustrating game of 
        "whack-a-mole." That's the carnival game where the player strikes at a 
        mechanical mole; it retreats and another mole pops up on the opposite side 
        of the field. The moles pop up and down so fast that you end up flailing 
        your mallet helplessly as the moles continue to pop up where you least 
        expect them.
      </p>
  image_url = /images/utc.jpg
 created_at = 2010-08-07 13:14:15.571988
 updated_at = 2010-08-07 13:14:15.571988
      price = 27.75
sqlite3> select * from line_items
         id = 1
 product_id = 3
   order_id = 1
   quantity = 1
total_price = 28.5
 created_at = 2010-08-07 13:15:14.981394
 updated_at = 2010-08-07 13:15:14.981394
curl --silent http://localhost:3000/info/who_bought/3
<order_list for_product="Pragmatic Version Control">
  <order>
    <name>Dave Thomas</name>
    <email>customer@example.com</email>
  </order>
</order_list>
edit app/views/info/who_bought.html.erb
<h3>People Who Bought <%= @product.title %></h3>
 
<ul>
  <% for order in @orders  -%>
    <li>
        <%= mail_to order.email, order.name %>
    </li>
  <%  end -%>
</ul>
edit app/controllers/info_controller.rb
class InfoController < ApplicationController
  def who_bought
    @product = Product.find(params[:id])
    @orders  = @product.orders
    respond_to do |format|
      format.html
      format.xml { render :layout => false }
    end
  end
 
protected
 
  def authorize
  end
end
curl --silent -H "Accept: text/html" http://localhost:3000/info/who_bought/3
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- START:jit -->
<html>
<head>
  <title>Pragprog Books Online Store</title>
<!-- START:stylesheet -->
  <link href="/stylesheets/depot.css?1281186909" media="all" rel="stylesheet" type="text/css" />
<!-- END:stylesheet -->
  <script src="/javascripts/prototype.js?1281186805" type="text/javascript"></script>
<script src="/javascripts/effects.js?1281186805" type="text/javascript"></script>
<script src="/javascripts/dragdrop.js?1281186805" type="text/javascript"></script>
<script src="/javascripts/controls.js?1281186805" type="text/javascript"></script>
<script src="/javascripts/rails.js?1281186805" type="text/javascript"></script>
<script src="/javascripts/application.js?1281186805" type="text/javascript"></script>
</head>
<!-- END:jit -->
<body id="store">
  <div id="banner">
    <img alt="Logo" src="/images/logo.png?1281186856" />
    Pragmatic Bookshelf
  </div>
  <div id="columns">
    <div id="side">
      <!-- START:hidden_div -->
<!-- START_HIGHLIGHT -->
<!-- END_HIGHLIGHT -->
    <!-- END:hidden_div -->
 
      <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 />
 
      <!-- START_HIGHLIGHT -->
      <!-- END_HIGHLIGHT -->
    </div>
    <div id="main">
      <!-- START:flash -->
      <!-- END:flash -->
 
      <h3>People Who Bought Pragmatic Version Control</h3>
 
<ul>
    <li>
        <a href="mailto:customer@example.com">Dave Thomas</a>
    </li>
</ul>
 
    </div>
  </div>
</body>
</html>
curl --silent -H "Accept: application/xml" http://localhost:3000/info/who_bought/3
<order_list for_product="Pragmatic Version Control">
  <order>
    <name>Dave Thomas</name>
    <email>customer@example.com</email>
  </order>
</order_list>
cp app/controllers/info_controller.rb app/controllers/info_controller.save
edit app/controllers/info_controller.rb
class InfoController < ApplicationController
  def who_bought
    @product = Product.find(params[:id])
    @orders  = @product.orders
    respond_to do |format|
      format.html
      format.xml { render :layout => false ,
                   :xml => @product.to_xml(:include => :orders) }
    end
  end
 
protected
 
  def authorize
  end
end
curl --silent http://localhost:3000/info/who_bought/3.xml
<?xml version="1.0" encoding="UTF-8"?>
<product>
  <price type="decimal">28.5</price>
  <created-at type="datetime">2010-08-07T13:14:15Z</created-at>
  <image-url>/images/svn.jpg</image-url>
  <title>Pragmatic Version Control</title>
  <updated-at type="datetime">2010-08-07T13:14:15Z</updated-at>
  <id type="integer">3</id>
  <description>&lt;p&gt;
         This book is a recipe-based approach to using Subversion that will 
         get you up and running quickly---and correctly. All projects need
         version control: it's a foundational piece of any project's 
         infrastructure. Yet half of all project teams in the U.S. don't use
         any version control at all. Many others don't use it well, and end 
         up experiencing time-consuming problems.
      &lt;/p&gt;</description>
  <orders type="array">
    <order>
      <address>123 Main St</address>
      <name>Dave Thomas</name>
      <created-at type="datetime">2010-08-07T13:15:14Z</created-at>
      <updated-at type="datetime">2010-08-07T13:15:14Z</updated-at>
      <pay-type>check</pay-type>
      <id type="integer">1</id>
      <email>customer@example.com</email>
    </order>
  </orders>
</product>
edit app/views/info/who_bought.atom.builder
atom_feed do |feed|
  feed.title "Who bought #{@product.title}"
  feed.updated @orders.first.created_at
 
  for order in @orders
    feed.entry(order) do |entry|
      entry.title "Order #{order.id}"
      entry.summary :type => 'xhtml' do |xhtml|
        xhtml.p "Shipped to #{order.address}"
 
        xhtml.table do
          xhtml.tr do
            xhtml.th 'Product'
            xhtml.th 'Quantity'
            xhtml.th 'Total Price'
          end
          for item in order.line_items
            xhtml.tr do
              xhtml.td item.product.title
              xhtml.td item.quantity
              xhtml.td number_to_currency item.total_price
            end
          end
          xhtml.tr do
            xhtml.th 'total', :colspan => 2
            xhtml.th number_to_currency \
              order.line_items.map(&:total_price).sum
          end
        end
 
        xhtml.p "Paid by #{order.pay_type}"
      end
      entry.author do |author|
        entry.name order.name
        entry.email order.email
      end
    end
  end
end
edit app/controllers/info_controller.rb
class InfoController < ApplicationController
  def who_bought
    @product = Product.find(params[:id])
    @orders  = @product.orders
    respond_to do |format|
      format.html
      format.atom { render :layout => false }
      format.xml { render :layout => false ,
                   :xml => @product.to_xml(:include => :orders) }
    end
  end
 
protected
 
  def authorize
  end
end
curl --silent http://localhost:3000/info/who_bought/3.atom
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <id>tag:localhost,2005:/info/who_bought/3</id>
  <link type="text/html" rel="alternate" href="http://localhost:3000"/>
  <link type="application/atom+xml" rel="self" href="http://localhost:3000/info/who_bought/3.atom"/>
  <title>Who bought Pragmatic Version Control</title>
  <updated>2010-08-07T13:15:14Z</updated>
  <entry>
    <id>tag:localhost,2005:Order/1</id>
    <published>2010-08-07T13:15:14Z</published>
    <updated>2010-08-07T13:15:14Z</updated>
    <link type="text/html" rel="alternate" href="http://localhost:3000/orders/1"/>
    <title>Order 1</title>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Shipped to 123 Main St</p>
        <table>
          <tr>
            <th>Product</th>
            <th>Quantity</th>
            <th>Total Price</th>
          </tr>
          <tr>
            <td>Pragmatic Version Control</td>
            <td>1</td>
            <td>$28.50</td>
          </tr>
          <tr>
            <th colspan="2">total</th>
            <th>$28.50</th>
          </tr>
        </table>
        <p>Paid by check</p>
      </div>
    </summary>
    <author>
      <name>Dave Thomas</name>
      <email>customer@example.com</email>
    </author>
  </entry>
</feed>
edit app/controllers/info_controller.rb
class InfoController < ApplicationController
  def who_bought
    @product = Product.find(params[:id])
    @orders  = @product.orders
    respond_to do |format|
      format.html
      format.atom { render :layout => false }
      format.xml { render :layout => false ,
                   :xml => @product.to_xml(:include => :orders) }
      format.json { render :layout => false ,
                   :json => @product.to_json(:include => :orders) }
    end
  end
 
protected
 
  def authorize
  end
end
curl --silent -H "Accept: application/json" http://localhost:3000/info/who_bought/3
{"product":{"price":"28.5","created_at":"2010-08-07T13:14:15Z","orders":[{"name":"Dave Thomas","address":"123 Main St","created_at":"2010-08-07T13:15:14Z","updated_at":"2010-08-07T13:15:14Z","pay_type":"check","id":1,"email":"customer@example.com"}],"title":"Pragmatic Version Control","image_url":"/images/svn.jpg","updated_at":"2010-08-07T13:14:15Z","id":3,"description":"<p>\n         This book is a recipe-based approach to using Subversion that will \n         get you up and running quickly---and correctly. All projects need\n         version control: it's a foundational piece of any project's \n         infrastructure. Yet half of all project teams in the U.S. don't use\n         any version control at all. Many others don't use it well, and end \n         up experiencing time-consuming problems.\n      </p>"}}
mv app/controllers/info_controller.save app/controllers/info_controller.rb
rake doc:app
rm -r doc/app

    
                     README_FOR_APP: 
              application_helper.rb: m
                    store_helper.rb: m.
                     info_helper.rb: m
                    admin_helper.rb: m
               line_items_helper.rb: m
                   orders_helper.rb: m
                    users_helper.rb: m
                 products_helper.rb: m
                users_controller.rb: c.......
                store_controller.rb: c........
           line_items_controller.rb: c.......
          application_controller.rb: c.
                 info_controller.rb: c..
                admin_controller.rb: c...
             products_controller.rb: c.......
               orders_controller.rb: c.......
                            cart.rb: c....
                       cart_item.rb: c....
                            user.rb: c.......
                         product.rb: c..
                       line_item.rb: c.
                           order.rb: c.
Generating HTML...
(in /home/rubys/git/awdwr/work-188/depot)
 
Files:   23
Classes: 14
Modules: 8
Methods: 62
Elapsed: 0.804s
rake stats
(in /home/rubys/git/awdwr/work-188/depot)
+----------------------+-------+-------+---------+---------+-----+-------+
| Name                 | Lines |   LOC | Classes | Methods | M/C | LOC/M |
+----------------------+-------+-------+---------+---------+-----+-------+
| Controllers          |   503 |   337 |       8 |      42 |   5 |     6 |
| Helpers              |    22 |    22 |       0 |       1 |   0 |    20 |
| Models               |   231 |   130 |       6 |      19 |   3 |     4 |
| Libraries            |     0 |     0 |       0 |       0 |   0 |     0 |
| Integration tests    |     0 |     0 |       0 |       0 |   0 |     0 |
| Functional tests     |   233 |   185 |       7 |       0 |   0 |     0 |
| Unit tests           |    60 |    45 |      11 |       0 |   0 |     0 |
+----------------------+-------+-------+---------+---------+-----+-------+
| Total                |  1049 |   719 |      32 |      62 |   1 |     9 |
+----------------------+-------+-------+---------+---------+-----+-------+
  Code LOC: 489     Test LOC: 230     Code to Test Ratio: 1:0.5
 

13 Task I: Internationalization 11.4 Iteration F4: Adding a Sidebar, More Administration