Finished chapter 6
authorNeil Smith <neil.git@njae.me.uk>
Fri, 30 Jan 2009 11:56:47 +0000 (11:56 +0000)
committerNeil Smith <neil.git@njae.me.uk>
Fri, 30 Jan 2009 11:56:47 +0000 (11:56 +0000)
12 files changed:
app/models/product.rb
app/views/layouts/products.html.erb
app/views/products/edit.html.erb
app/views/products/index.html.erb
app/views/products/new.html.erb
app/views/products/show.html.erb
config/environment.rb
db/migrate/20090128142730_add_product_price.rb [new file with mode: 0644]
db/migrate/20090130111521_add_test_data.rb [new file with mode: 0644]
db/schema.rb
log/development.log
public/stylesheets/depot.css [new file with mode: 0644]

index 077a8197956de5d49c2de53c2b9aefd6e8477ff8..05ac26e38d4bc58dc371a9f3c5c649cab0bdebea 100644 (file)
@@ -1,2 +1,14 @@
 class Product < ActiveRecord::Base
+  validates_presence_of :title, :description, :image_url
+  validates_numericality_of :price
+  validate :price_must_be_at_least_a_penny
+  validates_uniqueness_of :title
+  validates_format_of :image_url,
+                      :with    => %r{\.(gif|jpg|png)$}i,
+                      :message => 'must be a URL for a GIF, JPG, or PNG image.'
+  
+protected
+  def price_must_be_at_least_a_penny
+    errors.add(:price, 'should be at least 0.01') if price.nil? || price < 0.01
+  end
 end
index b9f60bea28d725a0eae34ef515298e9d5d9b2313..07fed7f56389c3cc7fcb5d2a946bedda7b5ab112 100644 (file)
@@ -5,7 +5,7 @@
 <head>
   <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
   <title>Products: <%= controller.action_name %></title>
-  <%= stylesheet_link_tag 'scaffold' %>
+  <%= stylesheet_link_tag 'scaffold', 'depot' %>
 </head>
 <body>
 
index af3b7473f3329b0a2c7bb9870e66a0e39f72670a..7aa095b3f9eb37d4d1bee0a5a835546ff2cdf09e 100644 (file)
     <%= f.label :image_url %><br />
     <%= f.text_field :image_url %>
   </p>
+  <p>
+    <%= f.label :price %><br />
+    <%= f.text_field :price %>
+  </p>
   <p>
     <%= f.submit "Update" %>
   </p>
index 88120ee7e05a27a417f52f7b280dd760a9ecc1a8..1db53b8ae0b6cd45edcbf1a908b3dbc492abb82f 100644 (file)
@@ -1,24 +1,34 @@
-<h1>Listing products</h1>
+<div id="product-list">
+  <h1>Listing products</h1>
 
-<table>
-  <tr>
-    <th>Title</th>
-    <th>Description</th>
-    <th>Image url</th>
-  </tr>
+  <table>
+  <% for product in @products %>
+     <tr class="<%= cycle('list-line-odd', 'list-line-even')%>">
 
-<% for product in @products %>
-  <tr>
-    <td><%=h product.title %></td>
-    <td><%=h product.description %></td>
-    <td><%=h product.image_url %></td>
-    <td><%= link_to 'Show', product %></td>
-    <td><%= link_to 'Edit', edit_product_path(product) %></td>
-    <td><%= link_to 'Destroy', product, :confirm => 'Are you sure?', :method => :delete %></td>
-  </tr>
-<% end %>
-</table>
+        <td>
+          <%= image_tag product.image_url, :class => 'list-image' %>
+        </td>
 
-<br />
+        <td class="list-description">
+          <dl>
+            <dt><%= h product.title %></dt>
+            <dd><%= h truncate(product.description.gsub(/<.*?>/, ''),
+                :length => 80) %></dd>
+            </dl>
+        </td>
+
+        <td class="list-actions">
+            <%= link_to 'Show', product %><br/>
+            <%= link_to 'Edit', edit_product_path(product) %><br/>
+            <%= link_to 'Destroy', product, 
+              :confirm => 'Are you sure?', 
+              :method => :delete %>
+        </td>
+    </tr>
+  <% end %>
+  </table>
+</div>
+
+<br/>
 
 <%= link_to 'New product', new_product_path %>
index f93593799e4963301c96ddaf4aa8f6e73d1956fa..90ef7f2e0edd275a50db49820fc78281d92aebe5 100644 (file)
     <%= f.label :image_url %><br />
     <%= f.text_field :image_url %>
   </p>
-  <p>
+   <p>
+    <%= f.label :price %><br />
+    <%= f.text_field :price %>
+  </p>
+ <p>
     <%= f.submit "Create" %>
   </p>
 <% end %>
index a5f0eac8b6a295687cc4eee5913c7638bb8f29fc..124ab7756fce492c1c0b81c591bc175b8d9f7e34 100644 (file)
   <%=h @product.image_url %>
 </p>
 
+<p>
+  <b>Price:</b>
+  <%=h @product.price %>
+</p>
+
 
 <%= link_to 'Edit', edit_product_path(@product) %> |
 <%= link_to 'Back', products_path %>
index 73cc3e428169c3e4550bbc2bc8001dc336b04c4e..bedc82cc08a5c1a78a9accb0a9b087c36209191f 100644 (file)
@@ -5,7 +5,8 @@
 # ENV['RAILS_ENV'] ||= 'production'
 
 # Specifies gem version of Rails to use when vendor/rails is not present
-RAILS_GEM_VERSION = '2.1.0' unless defined? RAILS_GEM_VERSION
+# RAILS_GEM_VERSION = '2.1.0' unless defined? RAILS_GEM_VERSION
+RAILS_GEM_VERSION = '2.2.2' unless defined? RAILS_GEM_VERSION
 
 # Bootstrap the Rails environment, frameworks, and default configuration
 require File.join(File.dirname(__FILE__), 'boot')
diff --git a/db/migrate/20090128142730_add_product_price.rb b/db/migrate/20090128142730_add_product_price.rb
new file mode 100644 (file)
index 0000000..f49426b
--- /dev/null
@@ -0,0 +1,9 @@
+class AddProductPrice < ActiveRecord::Migration
+  def self.up
+    add_column :products, :price, :decimal, :precision => 8, :scale => 2, :default => 0
+  end
+
+  def self.down
+    remove_column :products, :price
+  end
+end
diff --git a/db/migrate/20090130111521_add_test_data.rb b/db/migrate/20090130111521_add_test_data.rb
new file mode 100644 (file)
index 0000000..975146e
--- /dev/null
@@ -0,0 +1,56 @@
+class AddTestData < ActiveRecord::Migration
+  def self.up
+    Product.delete_all
+    Product.create(: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&mdash;and difficult&mdash;stuff, like writing quality code.
+        </p>},
+      :image_url => '/images/auto.jpg',
+      :price => 29.95)
+
+    Product.create(:title => 'Pragmatic Version Control',
+      :description =>
+        %{<p>
+          This book is a recipe-based approach to using Subversion that will 
+          get you up and running quickly&mdash;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',
+      :price => 28.50)
+
+    Product.create(: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',
+      :price => 27.75)
+
+  end
+
+  def self.down
+    Product.delete_all
+  end
+end
index c702c8e575506f57cc6dfe7332e5035a8a3724e0..b87309270457b2db59c6b2ed63fbde255b000724 100644 (file)
@@ -9,7 +9,7 @@
 #
 # It's strongly recommended to check this file into your version control system.
 
-ActiveRecord::Schema.define(:version => 20080724075409) do
+ActiveRecord::Schema.define(:version => 20090130111521) do
 
   create_table "products", :force => true do |t|
     t.string   "title"
@@ -17,6 +17,7 @@ ActiveRecord::Schema.define(:version => 20080724075409) do
     t.string   "image_url"
     t.datetime "created_at"
     t.datetime "updated_at"
+    t.decimal  "price",       :precision => 8, :scale => 2, :default => 0.0
   end
 
 end
index 0057ea8dcf7f7ba5b8bdd9c2991a3dd5296b3e09..95b56a7e5cbaa665a32daa5b828a7690287b908a 100644 (file)
@@ -141,3 +141,443 @@ Rendering template within layouts/products
 Rendering products/index
   \e[4;35;1mProduct Columns (0.003374)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
 Completed in 0.02020 (49 reqs/sec) | Rendering: 0.00515 (25%) | DB: 0.00370 (18%) | 200 OK [http://localhost/products]
+  \e[4;36;1mSQL (0.3ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mSQL (17.9ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+Migrating to CreateProducts (20080724075409)
+Migrating to AddProductPrice (20090128142730)
+  \e[4;35;1mSQL (222.8ms)\e[0m   \e[0mALTER TABLE `products` ADD `price` decimal(8,2) DEFAULT 2\e[0m
+  \e[4;36;1mSQL (0.8ms)\e[0m   \e[0;1mINSERT INTO schema_migrations (version) VALUES ('20090128142730')\e[0m
+  \e[4;35;1mSQL (0.6ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.4ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+  \e[4;35;1mSQL (0.5ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (2.2ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mSQL (1.9ms)\e[0m   \e[0mdescribe `products`\e[0m
+  \e[4;36;1mSQL (1.0ms)\e[0m   \e[0;1mSHOW KEYS FROM `products`\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mSQL (0.5ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+Migrating to AddProductPrice (20090128142730)
+  \e[4;35;1mSQL (27.2ms)\e[0m   \e[0mALTER TABLE `products` DROP `price`\e[0m
+  \e[4;36;1mSQL (40.9ms)\e[0m   \e[0;1mDELETE FROM schema_migrations WHERE version = '20090128142730'\e[0m
+Migrating to CreateProducts (20080724075409)
+  \e[4;35;1mSQL (26.4ms)\e[0m   \e[0mDROP TABLE `products`\e[0m
+  \e[4;36;1mSQL (38.8ms)\e[0m   \e[0;1mDELETE FROM schema_migrations WHERE version = '20080724075409'\e[0m
+  \e[4;35;1mSQL (0.5ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.4ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+Migrating to CreateProducts (20080724075409)
+  \e[4;35;1mSQL (30.6ms)\e[0m   \e[0mCREATE TABLE `products` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `title` varchar(255), `description` text, `image_url` varchar(255), `created_at` datetime, `updated_at` datetime) ENGINE=InnoDB\e[0m
+  \e[4;36;1mSQL (25.8ms)\e[0m   \e[0;1mINSERT INTO schema_migrations (version) VALUES ('20080724075409')\e[0m
+Migrating to AddProductPrice (20090128142730)
+  \e[4;35;1mSQL (16.2ms)\e[0m   \e[0mALTER TABLE `products` ADD `price` decimal(8,2) DEFAULT 0\e[0m
+  \e[4;36;1mSQL (0.8ms)\e[0m   \e[0;1mINSERT INTO schema_migrations (version) VALUES ('20090128142730')\e[0m
+  \e[4;35;1mSQL (0.5ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.4ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+  \e[4;35;1mSQL (0.5ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (3.6ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mSQL (1.9ms)\e[0m   \e[0mdescribe `products`\e[0m
+  \e[4;36;1mSQL (0.6ms)\e[0m   \e[0;1mSHOW KEYS FROM `products`\e[0m
+
+
+Processing ProductsController#index (for 127.0.0.1 at 2009-01-30 10:55:37) [GET]
+  \e[4;36;1mSQL (41.3ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Load (49.7ms)\e[0m   \e[0mSELECT * FROM `products` \e[0m
+Rendering template within layouts/products
+Rendering products/index
+  \e[4;36;1mProduct Columns (23.1ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+Completed in 234ms (View: 147, DB: 114) | 200 OK [http://localhost/products]
+
+
+Processing ProductsController#edit (for 127.0.0.1 at 2009-01-30 10:55:41) [GET]
+  Parameters: {"id"=>"1"}
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;36;1mProduct Columns (1.1ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mProduct Load (23.3ms)\e[0m   \e[0mSELECT * FROM `products` WHERE (`products`.`id` = 1) \e[0m
+Rendering template within layouts/products
+Rendering products/edit
+Completed in 52ms (View: 16, DB: 24) | 200 OK [http://localhost/products/1/edit]
+
+
+Processing ProductsController#update (for 127.0.0.1 at 2009-01-30 10:55:42) [PUT]
+  Parameters: {"commit"=>"Update", "authenticity_token"=>"f081ce86efd30d00f8269cdde39c0b562c696c34", "product"=>{"image_url"=>"", "price"=>"17.00", "title"=>"First product", "description"=>"This is the description of the <i>first</i> product"}, "id"=>"1"}
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Columns (1.2ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+  \e[4;36;1mProduct Load (0.3ms)\e[0m   \e[0;1mSELECT * FROM `products` WHERE (`products`.`id` = 1) \e[0m
+  \e[4;35;1mSQL (0.7ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (62.9ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'First product' AND `products`.id <> 1) LIMIT 1\e[0m
+  \e[4;35;1mSQL (0.2ms)\e[0m   \e[0mROLLBACK\e[0m
+Rendering template within layouts/products
+Rendering products/edit
+Completed in 182ms (View: 22, DB: 65) | 200 OK [http://localhost/products/1]
+
+
+Processing ProductsController#update (for 127.0.0.1 at 2009-01-30 10:56:00) [PUT]
+  Parameters: {"commit"=>"Update", "authenticity_token"=>"f081ce86efd30d00f8269cdde39c0b562c696c34", "product"=>{"image_url"=>"prod1", "price"=>"17.00", "title"=>"First product", "description"=>"This is the description of the <i>first</i> product"}, "id"=>"1"}
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Columns (1.3ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+  \e[4;36;1mProduct Load (0.1ms)\e[0m   \e[0;1mSELECT * FROM `products` WHERE (`products`.`id` = 1) \e[0m
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.1ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'First product' AND `products`.id <> 1) LIMIT 1\e[0m
+  \e[4;35;1mSQL (0.2ms)\e[0m   \e[0mROLLBACK\e[0m
+Rendering template within layouts/products
+Rendering products/edit
+Completed in 42ms (View: 16, DB: 2) | 200 OK [http://localhost/products/1]
+
+
+Processing ProductsController#update (for 127.0.0.1 at 2009-01-30 10:56:04) [PUT]
+  Parameters: {"commit"=>"Update", "authenticity_token"=>"f081ce86efd30d00f8269cdde39c0b562c696c34", "product"=>{"image_url"=>"prod1.png", "price"=>"17.00", "title"=>"First product", "description"=>"This is the description of the <i>first</i> product"}, "id"=>"1"}
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Columns (1.1ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+  \e[4;36;1mProduct Load (0.2ms)\e[0m   \e[0;1mSELECT * FROM `products` WHERE (`products`.`id` = 1) \e[0m
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.1ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'First product' AND `products`.id <> 1) LIMIT 1\e[0m
+  \e[4;35;1mProduct Update (31.3ms)\e[0m   \e[0mUPDATE `products` SET `updated_at` = '2009-01-30 10:56:04', `image_url` = 'prod1.png' WHERE `id` = 1\e[0m
+  \e[4;36;1mSQL (8.9ms)\e[0m   \e[0;1mCOMMIT\e[0m
+Redirected to #<Product:0xb6716f18>
+Completed in 69ms (DB: 42) | 302 Found [http://localhost/products/1]
+
+
+Processing ProductsController#show (for 127.0.0.1 at 2009-01-30 10:56:04) [GET]
+  Parameters: {"id"=>"1"}
+  \e[4;35;1mSQL (0.2ms)\e[0m   \e[0mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;36;1mProduct Columns (2.4ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mProduct Load (0.6ms)\e[0m   \e[0mSELECT * FROM `products` WHERE (`products`.`id` = 1) \e[0m
+Rendering template within layouts/products
+Rendering products/show
+Completed in 43ms (View: 17, DB: 3) | 200 OK [http://localhost/products/1]
+
+
+Processing ProductsController#index (for 127.0.0.1 at 2009-01-30 10:56:07) [GET]
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Load (0.4ms)\e[0m   \e[0mSELECT * FROM `products` \e[0m
+Rendering template within layouts/products
+Rendering products/index
+  \e[4;36;1mProduct Columns (1.7ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+Completed in 28ms (View: 14, DB: 2) | 200 OK [http://localhost/products]
+
+
+Processing ProductsController#new (for 127.0.0.1 at 2009-01-30 10:56:13) [GET]
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;36;1mProduct Columns (1.1ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+Rendering template within layouts/products
+Rendering products/new
+Completed in 34ms (View: 21, DB: 1) | 200 OK [http://localhost/products/new]
+
+
+Processing ProductsController#create (for 127.0.0.1 at 2009-01-30 10:56:15) [POST]
+  Parameters: {"commit"=>"Create", "authenticity_token"=>"f081ce86efd30d00f8269cdde39c0b562c696c34", "product"=>{"image_url"=>"", "price"=>"0.0", "title"=>"", "description"=>""}}
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;36;1mProduct Columns (1.2ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.4ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY '') LIMIT 1\e[0m
+  \e[4;35;1mSQL (0.2ms)\e[0m   \e[0mROLLBACK\e[0m
+Rendering template within layouts/products
+Rendering products/new
+Completed in 49ms (View: 18, DB: 2) | 200 OK [http://localhost/products]
+
+
+Processing ProductsController#index (for 127.0.0.1 at 2009-01-30 10:56:26) [GET]
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Load (0.2ms)\e[0m   \e[0mSELECT * FROM `products` \e[0m
+Rendering template within layouts/products
+Rendering products/index
+  \e[4;36;1mProduct Columns (1.4ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+Completed in 32ms (View: 16, DB: 2) | 200 OK [http://localhost/products]
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.4ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+Migrating to CreateProducts (20080724075409)
+Migrating to AddProductPrice (20090128142730)
+Migrating to AddTestData (20090130111521)
+  \e[4;35;1mProduct Delete all (8.2ms)\e[0m   \e[0mDELETE FROM `products` \e[0m
+  \e[4;36;1mProduct Columns (1.7ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.4ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Version Control') LIMIT 1\e[0m
+  \e[4;35;1mProduct Create (28.2ms)\e[0m   \e[0mINSERT INTO `products` (`image_url`, `updated_at`, `title`, `price`, `description`, `created_at`) VALUES('/images/auto.jpg', '2009-01-30 11:21:28', 'Pragmatic Version Control', 29.95, '<p>\n <em>Pragmatic Project Automation</em> shows you how to improve the \n consistency and repeatability of your project\'s procedures using \n automation to reduce risk and errors.\n </p>\n <p>\n Simply put, we\'re going to put this thing called a computer to work \n for you doing the mundane (but important) project stuff. That means \n you\'ll have more time and energy to do the really \n exciting---and difficult---stuff, like writing quality code.\n </p>', '2009-01-30 11:21:28')\e[0m
+  \e[4;36;1mSQL (0.6ms)\e[0m   \e[0;1mCOMMIT\e[0m
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.4ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Version Control') LIMIT 1\e[0m
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mROLLBACK\e[0m
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mBEGIN\e[0m
+  \e[4;35;1mProduct Exists (0.4ms)\e[0m   \e[0mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Unit Testing (C#)') LIMIT 1\e[0m
+  \e[4;36;1mProduct Create (0.4ms)\e[0m   \e[0;1mINSERT INTO `products` (`image_url`, `updated_at`, `title`, `price`, `description`, `created_at`) VALUES('/images/utc.jpg', '2009-01-30 11:21:28', 'Pragmatic Unit Testing (C#)', 27.75, '<p>\n Pragmatic programmers use feedback to drive their development and \n personal processes. The most valuable feedback you can get while \n coding comes from unit testing.\n </p>\n <p>\n Without good tests in place, coding can become a frustrating game of \n \"whack-a-mole.\" That\'s the carnival game where the player strikes at a \n mechanical mole; it retreats and another mole pops up on the opposite side \n of the field. The moles pop up and down so fast that you end up flailing \n your mallet helplessly as the moles continue to pop up where you least \n expect them.\n </p>', '2009-01-30 11:21:28')\e[0m
+  \e[4;35;1mSQL (0.5ms)\e[0m   \e[0mCOMMIT\e[0m
+  \e[4;36;1mSQL (23.8ms)\e[0m   \e[0;1mINSERT INTO schema_migrations (version) VALUES ('20090130111521')\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.3ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+  \e[4;35;1mSQL (0.3ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (1.0ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mSQL (1.1ms)\e[0m   \e[0mdescribe `products`\e[0m
+  \e[4;36;1mSQL (0.5ms)\e[0m   \e[0;1mSHOW KEYS FROM `products`\e[0m
+
+
+Processing ProductsController#index (for 127.0.0.1 at 2009-01-30 11:21:36) [GET]
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;36;1mProduct Load (0.7ms)\e[0m   \e[0;1mSELECT * FROM `products` \e[0m
+Rendering template within layouts/products
+Rendering products/index
+  \e[4;35;1mProduct Columns (1.1ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+Completed in 34ms (View: 19, DB: 2) | 200 OK [http://localhost/products]
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+  \e[4;35;1mSQL (0.3ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+Migrating to AddTestData (20090130111521)
+  \e[4;35;1mProduct Delete all (7.2ms)\e[0m   \e[0mDELETE FROM `products` \e[0m
+  \e[4;36;1mSQL (9.5ms)\e[0m   \e[0;1mDELETE FROM schema_migrations WHERE version = '20090130111521'\e[0m
+Migrating to AddProductPrice (20090128142730)
+  \e[4;35;1mSQL (174.7ms)\e[0m   \e[0mALTER TABLE `products` DROP `price`\e[0m
+  \e[4;36;1mSQL (0.7ms)\e[0m   \e[0;1mDELETE FROM schema_migrations WHERE version = '20090128142730'\e[0m
+Migrating to CreateProducts (20080724075409)
+  \e[4;35;1mSQL (1.4ms)\e[0m   \e[0mDROP TABLE `products`\e[0m
+  \e[4;36;1mSQL (0.7ms)\e[0m   \e[0;1mDELETE FROM schema_migrations WHERE version = '20080724075409'\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.4ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+  \e[4;35;1mSQL (0.5ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mSQL (0.5ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+Migrating to CreateProducts (20080724075409)
+  \e[4;35;1mSQL (6.1ms)\e[0m   \e[0mCREATE TABLE `products` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `title` varchar(255), `description` text, `image_url` varchar(255), `created_at` datetime, `updated_at` datetime) ENGINE=InnoDB\e[0m
+  \e[4;36;1mSQL (0.8ms)\e[0m   \e[0;1mINSERT INTO schema_migrations (version) VALUES ('20080724075409')\e[0m
+Migrating to AddProductPrice (20090128142730)
+  \e[4;35;1mSQL (8.7ms)\e[0m   \e[0mALTER TABLE `products` ADD `price` decimal(8,2) DEFAULT 0\e[0m
+  \e[4;36;1mSQL (0.8ms)\e[0m   \e[0;1mINSERT INTO schema_migrations (version) VALUES ('20090128142730')\e[0m
+Migrating to AddTestData (20090130111521)
+  \e[4;35;1mProduct Delete all (9.7ms)\e[0m   \e[0mDELETE FROM `products` \e[0m
+  \e[4;36;1mProduct Columns (2.1ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mSQL (0.2ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.5ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Project Automation') LIMIT 1\e[0m
+  \e[4;35;1mProduct Create (0.4ms)\e[0m   \e[0mINSERT INTO `products` (`image_url`, `updated_at`, `title`, `price`, `description`, `created_at`) VALUES('/images/auto.jpg', '2009-01-30 11:22:38', 'Pragmatic Project Automation', 29.95, '<p>\n <em>Pragmatic Project Automation</em> shows you how to improve the \n consistency and repeatability of your project\'s procedures using \n automation to reduce risk and errors.\n </p>\n <p>\n Simply put, we\'re going to put this thing called a computer to work \n for you doing the mundane (but important) project stuff. That means \n you\'ll have more time and energy to do the really \n exciting---and difficult---stuff, like writing quality code.\n </p>', '2009-01-30 11:22:38')\e[0m
+  \e[4;36;1mSQL (0.6ms)\e[0m   \e[0;1mCOMMIT\e[0m
+  \e[4;35;1mSQL (0.2ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.4ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Version Control') LIMIT 1\e[0m
+  \e[4;35;1mProduct Create (0.4ms)\e[0m   \e[0mINSERT INTO `products` (`image_url`, `updated_at`, `title`, `price`, `description`, `created_at`) VALUES('/images/svn.jpg', '2009-01-30 11:22:38', 'Pragmatic Version Control', 28.5, '<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>', '2009-01-30 11:22:38')\e[0m
+  \e[4;36;1mSQL (0.6ms)\e[0m   \e[0;1mCOMMIT\e[0m
+  \e[4;35;1mSQL (0.2ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.4ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Unit Testing (C#)') LIMIT 1\e[0m
+  \e[4;35;1mProduct Create (0.5ms)\e[0m   \e[0mINSERT INTO `products` (`image_url`, `updated_at`, `title`, `price`, `description`, `created_at`) VALUES('/images/utc.jpg', '2009-01-30 11:22:38', 'Pragmatic Unit Testing (C#)', 27.75, '<p>\n Pragmatic programmers use feedback to drive their development and \n personal processes. The most valuable feedback you can get while \n coding comes from unit testing.\n </p>\n <p>\n Without good tests in place, coding can become a frustrating game of \n \"whack-a-mole.\" That\'s the carnival game where the player strikes at a \n mechanical mole; it retreats and another mole pops up on the opposite side \n of the field. The moles pop up and down so fast that you end up flailing \n your mallet helplessly as the moles continue to pop up where you least \n expect them.\n </p>', '2009-01-30 11:22:38')\e[0m
+  \e[4;36;1mSQL (6.3ms)\e[0m   \e[0;1mCOMMIT\e[0m
+  \e[4;35;1mSQL (13.7ms)\e[0m   \e[0mINSERT INTO schema_migrations (version) VALUES ('20090130111521')\e[0m
+  \e[4;36;1mSQL (0.5ms)\e[0m   \e[0;1mSHOW TABLES\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSELECT version FROM schema_migrations\e[0m
+  \e[4;36;1mSQL (0.5ms)\e[0m   \e[0;1mSHOW TABLES\e[0m
+  \e[4;35;1mSQL (1.8ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+  \e[4;36;1mSQL (1.8ms)\e[0m   \e[0;1mdescribe `products`\e[0m
+  \e[4;35;1mSQL (0.7ms)\e[0m   \e[0mSHOW KEYS FROM `products`\e[0m
+
+
+Processing ProductsController#index (for 127.0.0.1 at 2009-01-30 11:22:43) [GET]
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Load (0.4ms)\e[0m   \e[0mSELECT * FROM `products` \e[0m
+Rendering template within layouts/products
+Rendering products/index
+  \e[4;36;1mProduct Columns (1.1ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+Completed in 31ms (View: 17, DB: 2) | 200 OK [http://localhost/products]
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+  \e[4;35;1mSQL (0.3ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+Migrating to AddTestData (20090130111521)
+  \e[4;35;1mProduct Delete all (5.1ms)\e[0m   \e[0mDELETE FROM `products` \e[0m
+  \e[4;36;1mSQL (12.1ms)\e[0m   \e[0;1mDELETE FROM schema_migrations WHERE version = '20090130111521'\e[0m
+Migrating to AddProductPrice (20090128142730)
+  \e[4;35;1mSQL (30.2ms)\e[0m   \e[0mALTER TABLE `products` DROP `price`\e[0m
+  \e[4;36;1mSQL (0.7ms)\e[0m   \e[0;1mDELETE FROM schema_migrations WHERE version = '20090128142730'\e[0m
+Migrating to CreateProducts (20080724075409)
+  \e[4;35;1mSQL (2.0ms)\e[0m   \e[0mDROP TABLE `products`\e[0m
+  \e[4;36;1mSQL (6.3ms)\e[0m   \e[0;1mDELETE FROM schema_migrations WHERE version = '20080724075409'\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.4ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mSQL (1.2ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+Migrating to CreateProducts (20080724075409)
+  \e[4;35;1mSQL (3.4ms)\e[0m   \e[0mCREATE TABLE `products` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `title` varchar(255), `description` text, `image_url` varchar(255), `created_at` datetime, `updated_at` datetime) ENGINE=InnoDB\e[0m
+  \e[4;36;1mSQL (0.8ms)\e[0m   \e[0;1mINSERT INTO schema_migrations (version) VALUES ('20080724075409')\e[0m
+Migrating to AddProductPrice (20090128142730)
+  \e[4;35;1mSQL (6.6ms)\e[0m   \e[0mALTER TABLE `products` ADD `price` decimal(8,2) DEFAULT 0\e[0m
+  \e[4;36;1mSQL (0.7ms)\e[0m   \e[0;1mINSERT INTO schema_migrations (version) VALUES ('20090128142730')\e[0m
+Migrating to AddTestData (20090130111521)
+  \e[4;35;1mProduct Delete all (0.4ms)\e[0m   \e[0mDELETE FROM `products` \e[0m
+  \e[4;36;1mProduct Columns (1.1ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.6ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Project Automation') LIMIT 1\e[0m
+  \e[4;35;1mProduct Create (0.6ms)\e[0m   \e[0mINSERT INTO `products` (`image_url`, `updated_at`, `title`, `price`, `description`, `created_at`) VALUES('/images/auto.jpg', '2009-01-30 11:26:48', 'Pragmatic Project Automation', 29.95, '<p>\n <em>Pragmatic Project Automation</em> shows you how to improve the \n consistency and repeatability of your project\'s procedures using \n automation to reduce risk and errors.\n </p>\n <p>\n Simply put, we\'re going to put this thing called a computer to work \n for you doing the mundane (but important) project stuff. That means \n you\'ll have more time and energy to do the really \n exciting---and difficult---stuff, like writing quality code.\n </p>', '2009-01-30 11:26:48')\e[0m
+  \e[4;36;1mSQL (0.7ms)\e[0m   \e[0;1mCOMMIT\e[0m
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.4ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Version Control') LIMIT 1\e[0m
+  \e[4;35;1mProduct Create (1.0ms)\e[0m   \e[0mINSERT INTO `products` (`image_url`, `updated_at`, `title`, `price`, `description`, `created_at`) VALUES('/images/svn.jpg', '2009-01-30 11:26:48', 'Pragmatic Version Control', 28.5, '<p>\n This book is a recipe-based approach to using Subversion that will \n get you up and running quickly&emdash;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>', '2009-01-30 11:26:48')\e[0m
+  \e[4;36;1mSQL (1.8ms)\e[0m   \e[0;1mCOMMIT\e[0m
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.4ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Unit Testing (C#)') LIMIT 1\e[0m
+  \e[4;35;1mProduct Create (0.4ms)\e[0m   \e[0mINSERT INTO `products` (`image_url`, `updated_at`, `title`, `price`, `description`, `created_at`) VALUES('/images/utc.jpg', '2009-01-30 11:26:48', 'Pragmatic Unit Testing (C#)', 27.75, '<p>\n Pragmatic programmers use feedback to drive their development and \n personal processes. The most valuable feedback you can get while \n coding comes from unit testing.\n </p>\n <p>\n Without good tests in place, coding can become a frustrating game of \n \"whack-a-mole.\" That\'s the carnival game where the player strikes at a \n mechanical mole; it retreats and another mole pops up on the opposite side \n of the field. The moles pop up and down so fast that you end up flailing \n your mallet helplessly as the moles continue to pop up where you least \n expect them.\n </p>', '2009-01-30 11:26:48')\e[0m
+  \e[4;36;1mSQL (2.0ms)\e[0m   \e[0;1mCOMMIT\e[0m
+  \e[4;35;1mSQL (8.2ms)\e[0m   \e[0mINSERT INTO schema_migrations (version) VALUES ('20090130111521')\e[0m
+  \e[4;36;1mSQL (0.4ms)\e[0m   \e[0;1mSHOW TABLES\e[0m
+  \e[4;35;1mSQL (0.3ms)\e[0m   \e[0mSELECT version FROM schema_migrations\e[0m
+  \e[4;36;1mSQL (0.3ms)\e[0m   \e[0;1mSHOW TABLES\e[0m
+  \e[4;35;1mSQL (1.0ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+  \e[4;36;1mSQL (1.0ms)\e[0m   \e[0;1mdescribe `products`\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW KEYS FROM `products`\e[0m
+
+
+Processing ProductsController#index (for 127.0.0.1 at 2009-01-30 11:26:52) [GET]
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;36;1mProduct Load (0.4ms)\e[0m   \e[0;1mSELECT * FROM `products` \e[0m
+Rendering template within layouts/products
+Rendering products/index
+  \e[4;35;1mProduct Columns (1.1ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+Completed in 37ms (View: 24, DB: 2) | 200 OK [http://localhost/products]
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+  \e[4;35;1mSQL (0.5ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+Migrating to AddTestData (20090130111521)
+  \e[4;35;1mProduct Delete all (12.5ms)\e[0m   \e[0mDELETE FROM `products` \e[0m
+  \e[4;36;1mSQL (12.4ms)\e[0m   \e[0;1mDELETE FROM schema_migrations WHERE version = '20090130111521'\e[0m
+Migrating to AddProductPrice (20090128142730)
+  \e[4;35;1mSQL (22.2ms)\e[0m   \e[0mALTER TABLE `products` DROP `price`\e[0m
+  \e[4;36;1mSQL (0.7ms)\e[0m   \e[0;1mDELETE FROM schema_migrations WHERE version = '20090128142730'\e[0m
+Migrating to CreateProducts (20080724075409)
+  \e[4;35;1mSQL (6.1ms)\e[0m   \e[0mDROP TABLE `products`\e[0m
+  \e[4;36;1mSQL (0.9ms)\e[0m   \e[0;1mDELETE FROM schema_migrations WHERE version = '20080724075409'\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.3ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW TABLES\e[0m
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mSELECT version FROM schema_migrations\e[0m
+Migrating to CreateProducts (20080724075409)
+  \e[4;35;1mSQL (4.6ms)\e[0m   \e[0mCREATE TABLE `products` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `title` varchar(255), `description` text, `image_url` varchar(255), `created_at` datetime, `updated_at` datetime) ENGINE=InnoDB\e[0m
+  \e[4;36;1mSQL (0.7ms)\e[0m   \e[0;1mINSERT INTO schema_migrations (version) VALUES ('20080724075409')\e[0m
+Migrating to AddProductPrice (20090128142730)
+  \e[4;35;1mSQL (7.3ms)\e[0m   \e[0mALTER TABLE `products` ADD `price` decimal(8,2) DEFAULT 0\e[0m
+  \e[4;36;1mSQL (0.8ms)\e[0m   \e[0;1mINSERT INTO schema_migrations (version) VALUES ('20090128142730')\e[0m
+Migrating to AddTestData (20090130111521)
+  \e[4;35;1mProduct Delete all (1.1ms)\e[0m   \e[0mDELETE FROM `products` \e[0m
+  \e[4;36;1mProduct Columns (2.5ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mSQL (0.2ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.5ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Project Automation') LIMIT 1\e[0m
+  \e[4;35;1mProduct Create (0.4ms)\e[0m   \e[0mINSERT INTO `products` (`image_url`, `updated_at`, `title`, `price`, `description`, `created_at`) VALUES('/images/auto.jpg', '2009-01-30 11:28:11', 'Pragmatic Project Automation', 29.95, '<p>\n <em>Pragmatic Project Automation</em> shows you how to improve the \n consistency and repeatability of your project\'s procedures using \n automation to reduce risk and errors.\n </p>\n <p>\n Simply put, we\'re going to put this thing called a computer to work \n for you doing the mundane (but important) project stuff. That means \n you\'ll have more time and energy to do the really \n exciting&mdash;and difficult&mdash;stuff, like writing quality code.\n </p>', '2009-01-30 11:28:11')\e[0m
+  \e[4;36;1mSQL (0.5ms)\e[0m   \e[0;1mCOMMIT\e[0m
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.4ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Version Control') LIMIT 1\e[0m
+  \e[4;35;1mProduct Create (0.3ms)\e[0m   \e[0mINSERT INTO `products` (`image_url`, `updated_at`, `title`, `price`, `description`, `created_at`) VALUES('/images/svn.jpg', '2009-01-30 11:28:11', 'Pragmatic Version Control', 28.5, '<p>\n This book is a recipe-based approach to using Subversion that will \n get you up and running quickly&mdash;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>', '2009-01-30 11:28:11')\e[0m
+  \e[4;36;1mSQL (0.5ms)\e[0m   \e[0;1mCOMMIT\e[0m
+  \e[4;35;1mSQL (0.2ms)\e[0m   \e[0mBEGIN\e[0m
+  \e[4;36;1mProduct Exists (0.6ms)\e[0m   \e[0;1mSELECT `products`.id FROM `products` WHERE (`products`.`title` = BINARY 'Pragmatic Unit Testing (C#)') LIMIT 1\e[0m
+  \e[4;35;1mProduct Create (0.3ms)\e[0m   \e[0mINSERT INTO `products` (`image_url`, `updated_at`, `title`, `price`, `description`, `created_at`) VALUES('/images/utc.jpg', '2009-01-30 11:28:11', 'Pragmatic Unit Testing (C#)', 27.75, '<p>\n Pragmatic programmers use feedback to drive their development and \n personal processes. The most valuable feedback you can get while \n coding comes from unit testing.\n </p>\n <p>\n Without good tests in place, coding can become a frustrating game of \n \"whack-a-mole.\" That\'s the carnival game where the player strikes at a \n mechanical mole; it retreats and another mole pops up on the opposite side \n of the field. The moles pop up and down so fast that you end up flailing \n your mallet helplessly as the moles continue to pop up where you least \n expect them.\n </p>', '2009-01-30 11:28:11')\e[0m
+  \e[4;36;1mSQL (1.3ms)\e[0m   \e[0;1mCOMMIT\e[0m
+  \e[4;35;1mSQL (0.7ms)\e[0m   \e[0mINSERT INTO schema_migrations (version) VALUES ('20090130111521')\e[0m
+  \e[4;36;1mSQL (0.9ms)\e[0m   \e[0;1mSHOW TABLES\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSELECT version FROM schema_migrations\e[0m
+  \e[4;36;1mSQL (0.3ms)\e[0m   \e[0;1mSHOW TABLES\e[0m
+  \e[4;35;1mSQL (1.0ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+  \e[4;36;1mSQL (1.3ms)\e[0m   \e[0;1mdescribe `products`\e[0m
+  \e[4;35;1mSQL (0.4ms)\e[0m   \e[0mSHOW KEYS FROM `products`\e[0m
+
+
+Processing ProductsController#index (for 127.0.0.1 at 2009-01-30 11:28:19) [GET]
+  \e[4;36;1mSQL (0.3ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Load (1.3ms)\e[0m   \e[0mSELECT * FROM `products` \e[0m
+Rendering template within layouts/products
+Rendering products/index
+  \e[4;36;1mProduct Columns (1.2ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+Completed in 30ms (View: 15, DB: 3) | 200 OK [http://localhost/products]
+
+
+Processing ProductsController#index (for 127.0.0.1 at 2009-01-30 11:53:52) [GET]
+  \e[4;35;1mSQL (0.2ms)\e[0m   \e[0mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;36;1mProduct Load (0.3ms)\e[0m   \e[0;1mSELECT * FROM `products` \e[0m
+Rendering template within layouts/products
+Rendering products/index
+  \e[4;35;1mProduct Columns (1.3ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+Completed in 41ms (View: 24, DB: 2) | 200 OK [http://localhost/products]
+
+
+Processing ProductsController#show (for 127.0.0.1 at 2009-01-30 11:53:55) [GET]
+  Parameters: {"id"=>"1"}
+  \e[4;36;1mSQL (0.2ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Columns (2.1ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+  \e[4;36;1mProduct Load (0.7ms)\e[0m   \e[0;1mSELECT * FROM `products` WHERE (`products`.`id` = 1) \e[0m
+Rendering template within layouts/products
+Rendering products/show
+Completed in 41ms (View: 20, DB: 3) | 200 OK [http://localhost/products/1]
+
+
+Processing ProductsController#show (for 127.0.0.1 at 2009-01-30 11:54:35) [GET]
+  Parameters: {"id"=>"3"}
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;36;1mProduct Columns (1.3ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mProduct Load (0.4ms)\e[0m   \e[0mSELECT * FROM `products` WHERE (`products`.`id` = 3) \e[0m
+Rendering template within layouts/products
+Rendering products/show
+Completed in 29ms (View: 14, DB: 2) | 200 OK [http://localhost/products/3]
+
+
+Processing ProductsController#index (for 127.0.0.1 at 2009-01-30 11:54:44) [GET]
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Load (0.3ms)\e[0m   \e[0mSELECT * FROM `products` \e[0m
+Rendering template within layouts/products
+Rendering products/index
+  \e[4;36;1mProduct Columns (1.2ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+Completed in 39ms (View: 24, DB: 2) | 200 OK [http://localhost/products]
+
+
+Processing ProductsController#show (for 127.0.0.1 at 2009-01-30 11:55:35) [GET]
+  Parameters: {"id"=>"3"}
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;36;1mProduct Columns (1.1ms)\e[0m   \e[0;1mSHOW FIELDS FROM `products`\e[0m
+  \e[4;35;1mProduct Load (0.1ms)\e[0m   \e[0mSELECT * FROM `products` WHERE (`products`.`id` = 3) \e[0m
+Rendering template within layouts/products
+Rendering products/show
+Completed in 27ms (View: 13, DB: 1) | 200 OK [http://localhost/products/3]
+
+
+Processing ProductsController#edit (for 127.0.0.1 at 2009-01-30 11:55:43) [GET]
+  Parameters: {"id"=>"2"}
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Columns (1.9ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+  \e[4;36;1mProduct Load (0.5ms)\e[0m   \e[0;1mSELECT * FROM `products` WHERE (`products`.`id` = 2) \e[0m
+Rendering template within layouts/products
+Rendering products/edit
+Completed in 33ms (View: 18, DB: 2) | 200 OK [http://localhost/products/2/edit]
+
+
+Processing ProductsController#index (for 127.0.0.1 at 2009-01-30 11:56:05) [GET]
+  \e[4;35;1mSQL (0.2ms)\e[0m   \e[0mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;36;1mProduct Load (0.2ms)\e[0m   \e[0;1mSELECT * FROM `products` \e[0m
+Rendering template within layouts/products
+Rendering products/index
+  \e[4;35;1mProduct Columns (1.1ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+Completed in 35ms (View: 20, DB: 1) | 200 OK [http://localhost/products]
+
+
+Processing ProductsController#show (for 127.0.0.1 at 2009-01-30 11:56:08) [GET]
+  Parameters: {"id"=>"2"}
+  \e[4;36;1mSQL (0.1ms)\e[0m   \e[0;1mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;35;1mProduct Columns (1.1ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+  \e[4;36;1mProduct Load (0.2ms)\e[0m   \e[0;1mSELECT * FROM `products` WHERE (`products`.`id` = 2) \e[0m
+Rendering template within layouts/products
+Rendering products/show
+Completed in 26ms (View: 12, DB: 1) | 200 OK [http://localhost/products/2]
+
+
+Processing ProductsController#index (for 127.0.0.1 at 2009-01-30 11:56:25) [GET]
+  \e[4;35;1mSQL (0.1ms)\e[0m   \e[0mSET SQL_AUTO_IS_NULL=0\e[0m
+  \e[4;36;1mProduct Load (0.2ms)\e[0m   \e[0;1mSELECT * FROM `products` \e[0m
+Rendering template within layouts/products
+Rendering products/index
+  \e[4;35;1mProduct Columns (1.9ms)\e[0m   \e[0mSHOW FIELDS FROM `products`\e[0m
+Completed in 35ms (View: 21, DB: 2) | 200 OK [http://localhost/products]
diff --git a/public/stylesheets/depot.css b/public/stylesheets/depot.css
new file mode 100644 (file)
index 0000000..bb9c8b5
--- /dev/null
@@ -0,0 +1,141 @@
+/* Global styles */
+
+h1 {
+        font:  150% sans-serif;
+        color: #226;
+        border-bottom: 3px dotted #77d;
+}
+
+/* Styles for products/index */
+
+#product-list table {
+        border-collapse: collapse;
+}
+
+#product-list table tr td {
+        padding: 5px;
+        vertical-align: top;
+}
+
+#product-list .list-image {
+  width:        60px;
+  height:       70px;
+}
+
+#product-list .list-description {
+  width:        60%;
+}
+
+#product-list .list-description dl {
+        margin: 0;
+}
+
+#product-list .list-description dt {
+       color:        #244;
+       font-weight:  bold;
+       font-size:    larger;
+}
+
+#product-list .list-description dd {
+        margin: 0;
+}
+
+#product-list .list-actions {
+  font-size:    x-small;
+  text-align:   right;
+  padding-left: 1em;
+}
+
+#product-list .list-line-even {
+  background:   #e0f8f8;
+}
+
+#product-list .list-line-odd {
+  background:   #f8b0f8;
+}
+
+/* An entry in the store catalog */
+
+#store  .entry {
+  overflow: auto;
+  margin-top: 1em;
+  border-bottom: 1px dotted #77d;
+}
+
+#store  .title {
+  font-size: 120%;
+  font-family: sans-serif;
+}
+
+#store .entry img {
+  width: 75px;
+  float: left;
+}
+
+
+#store .entry h3 {
+ margin-top: 0;
+ margin-bottom: 2px;
+ color: #227;
+}
+
+#store .entry p {
+ margin-top: 0.5em; 
+ margin-bottom: 0.8em; 
+}
+
+#store .entry .price-line {
+ clear: both;
+}
+
+#store .entry .add-to-cart {
+  position: relative;
+}
+
+#store .entry  .price {
+  color: #44a;
+  font-weight: bold;
+  margin-right: 2em;
+}
+
+/* The error box */
+
+.fieldWithErrors {
+  padding: 2px;
+  background-color: #EEFFEE;
+  display: inline;
+}
+
+.fieldWithErrors * {
+  background-color: red;
+}
+
+#errorExplanation {
+  width: 400px;
+  border: 2px solid red;
+  padding: 7px;
+  padding-bottom: 12px;
+  margin-bottom: 20px;
+  background-color: #f0f0f0;
+}
+
+#errorExplanation h2 {
+  text-align: left;
+  font-weight: bold;
+  padding: 5px 5px 5px 15px;
+  font-size: 12px;
+  margin: -7px;
+  background-color: #c00;
+  color: #fff;
+}
+
+#errorExplanation p {
+  color: #333;
+  margin-bottom: 0;
+  padding: 5px;
+}
+
+#errorExplanation ul li {
+  font-size: 12px;
+  list-style: square;
+}