The Depot Application
Table of Contents
6.1 Iteration A1: Getting Something Running
ruby -rubygems C:\cygwin\home\rubys\git\rails\railties\bin\rails depot
create
create README
create .gitignore
create Rakefile
create config.ru
create Gemfile
create app
create app/controllers/application_controller.rb
create app/helpers/application_helper.rb
create app/models
create app/views/layouts
create config
create config/routes.rb
create config/application.rb
create config/environment.rb
create config/environments
create config/environments/development.rb
create config/environments/production.rb
create config/environments/test.rb
create config/initializers
create config/initializers/backtrace_silencers.rb
create config/initializers/cookie_verification_secret.rb
create config/initializers/inflections.rb
create config/initializers/mime_types.rb
create config/initializers/session_store.rb
create config/locales
create config/locales/en.yml
create config/boot.rb
create config/database.yml
create db
create db/seeds.rb
create doc
create doc/README_FOR_APP
create lib
create lib/tasks
create lib/tasks/.gitkeep
create log
create log/server.log
create log/production.log
create log/development.log
create log/test.log
create public
create public/404.html
create public/422.html
create public/500.html
create public/favicon.ico
create public/index.html
create public/robots.txt
create public/images
create public/images/rails.png
create public/stylesheets
create public/stylesheets/.gitkeep
create public/javascripts
create public/javascripts/application.js
create public/javascripts/controls.js
create public/javascripts/dragdrop.js
create public/javascripts/effects.js
create public/javascripts/prototype.js
create public/javascripts/rails.js
create script
create script/rails
create test
create test/performance/browsing_test.rb
create test/test_helper.rb
create test/fixtures
create test/functional
create test/integration
create test/unit
create tmp
create tmp/sessions
create tmp/sockets
create tmp/cache
create tmp/pids
create vendor/plugins
create vendor/plugins/.gitkeep
bundle install
Resolving dependencies
Installing abstract (1.0.0) from system gems
Installing actionmailer (3.0.0.beta1) from source code at C:/cygwin/home/rubys/git/rails
Installing actionpack (3.0.0.beta1) from source code at C:/cygwin/home/rubys/git/rails
Installing activemodel (3.0.0.beta1) from source code at C:/cygwin/home/rubys/git/rails
Installing activerecord (3.0.0.beta1) from source code at C:/cygwin/home/rubys/git/rails
Installing activeresource (3.0.0.beta1) from source code at C:/cygwin/home/rubys/git/rails
Installing activesupport (3.0.0.beta1) from source code at C:/cygwin/home/rubys/git/rails
Installing arel (0.2.1) from system gems
Installing builder (2.1.2) from system gems
Installing bundler (0.9.8) from system gems
Installing erubis (2.6.5) from system gems
Installing i18n (0.3.3) from system gems
Installing mail (2.1.3) from system gems
Installing memcache-client (1.7.8) from system gems
Installing mime-types (1.16) from system gems
Installing rack (1.1.0) from system gems
Installing rack-mount (0.5.2) from system gems
Installing rack-test (0.5.3) from system gems
Installing rails (3.0.0.beta1) from source code at C:/cygwin/home/rubys/git/rails
Installing railties (3.0.0.beta1) from source code at C:/cygwin/home/rubys/git/rails
Installing rake (0.8.7) from system gems
Installing sqlite3-ruby (1.2.5) from system gems
Installing text-format (1.0.0) from system gems
Installing text-hyphen (1.0.0) from system gems
Installing thor (0.13.3) from system gems
Installing tzinfo (0.3.16) from system gems
Your bundle is complete!
edit config\routes.rb
Depot::Application.routes.draw do |map|
# ...
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
match ':controller(/:action(/:id(.:format)))'
end
6.2 Creating the Products Model and Maintenance Application
dir/w
Volume in drive C is ACER
Volume Serial Number is 0412-C06E
Directory of C:\cygwin\home\rubys\git\awdwr\work\depot
[.] [..] [.bundle] .gitignore [app] [config]
config.ru [db] [doc] Gemfile [lib] [log]
[public] Rakefile README [script] [test] [tmp]
[vendor]
5 File(s) 11,147 bytes
14 Dir(s) 99,148,570,624 bytes free
ruby script\rails generate scaffold product title:string description:text image_url:string
invoke active_record
create db/migrate/20100225154712_create_products.rb
create app/models/product.rb
invoke test_unit
create test/unit/product_test.rb
create test/fixtures/products.yml
route resources :products
invoke scaffold_controller
create app/controllers/products_controller.rb
invoke erb
create app/views/products
create app/views/products/index.html.erb
create app/views/products/edit.html.erb
create app/views/products/show.html.erb
create app/views/products/new.html.erb
create app/views/products/_form.html.erb
create app/views/layouts/products.html.erb
invoke test_unit
create test/functional/products_controller_test.rb
invoke helper
create app/helpers/products_helper.rb
invoke test_unit
create test/unit/helpers/products_helper_test.rb
invoke stylesheets
create public/stylesheets/scaffold.css
rake db:migrate
mv 20100225154712_create_products.rb 20100301000001_create_products.rb
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
== CreateProducts: migrating =================================================
-- create_table(:products)
-> 0.0020s
== CreateProducts: migrated (0.0030s) ========================================
sqlite3> select version from schema_migrations
version = 20100301000001
Start the server.
edit app\views\products\_form.html.erb
<% form_for(@product) do |f| %>
<%= f.error_messages %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description, :rows => 6 %>
</div>
<div class="field">
<%= f.label :image_url %><br />
<%= f.text_field :image_url %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
get /products
Listing products
Title
Description
Image url
New product
get /products/new
post /products
product[image_url] => /images/svn.jpg
product[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. dont use any version
control at all. Many others dont use it
well, and end up experiencing
time-consuming problems.
</p>
product[title] => Pragmatic Version Control
You are being
redirected .
get http://localhost:3000/products/1
Product was successfully created.
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. dont use any version
control at all. Many others dont use it
well, and end up experiencing
time-consuming problems.
</p>
Image url:
/images/svn.jpg
Edit |
Back
get /products
Listing products
Title
Description
Image url
Pragmatic Version Control
<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. dont use any version
control at all. Many others dont use it
well, and end up experiencing
time-consuming problems.
</p>
/images/svn.jpg
Show
Edit
Destroy
New product
sqlite3 db\development.sqlite3 .schema
CREATE TABLE "products" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(255), "description" text, "image_url" varchar(255), "created_at" datetime, "updated_at" datetime);
CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL);
CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version");
rake test
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
Loaded suite C:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
.
Finished in 0.24 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
Loaded suite C:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
.......
Finished in 0.6 seconds.
7 tests, 10 assertions, 0 failures, 0 errors
6.3 Iteration A2: Add a Missing Column
ruby script\rails generate migration add_price_to_product price:decimal
invoke active_record
create db/migrate/20100225154753_add_price_to_product.rb
type db\migrate\20100225154753_add_price_to_product.rb
class AddPriceToProduct < ActiveRecord::Migration
def self.up
add_column :products, :price, :decimal
end
def self.down
remove_column :products, :price
end
end
edit db\migrate\20100225154753_add_price_to_product.rb
class AddPriceToProduct < 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
rake db:migrate
mv 20100225154753_add_price_to_product.rb 20100301000002_add_price_to_product.rb
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
== AddPriceToProduct: migrating ==============================================
-- add_column(:products, :price, :decimal, {:scale=>2, :default=>0, :precision=>8})
-> 0.0110s
== AddPriceToProduct: migrated (0.0110s) =====================================
sqlite3 db\development.sqlite3 .schema
CREATE TABLE "products" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(255), "description" text, "image_url" varchar(255), "created_at" datetime, "updated_at" datetime, "price" decimal(8,2) DEFAULT 0);
CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL);
CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version");
edit app\views\products\index.html.erb
<h1>Listing products</h1>
<table>
<tr>
<th>Title</th>
<th>Description</th>
<th>Image url</th>
<th>Price</th>
<th></th>
<th></th>
<th></th>
</tr>
<% @products.each do |product| %>
<tr>
<td><%= product.title %></td>
<td><%= product.description %></td>
<td><%= product.image_url %></td>
<td><%= product.price %></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>
<br />
<%= link_to 'New product', new_product_path %>
edit app\views\products\_form.html.erb
<% form_for(@product) do |f| %>
<%= f.error_messages %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description, :rows => 6 %>
</div>
<div class="field">
<%= f.label :image_url %><br />
<%= f.text_field :image_url %>
</div>
<div class="field">
<%= f.label :price %><br />
<%= f.text_field :price %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
edit app\views\products\show.html.erb
<p>
<b>Title:</b>
<%= @product.title %>
</p>
<p>
<b>Description:</b>
<%= @product.description %>
</p>
<p>
<b>Image url:</b>
<%= @product.image_url %>
</p>
<p>
<b>Price:</b>
<%= @product.price %>
</p>
<%= link_to 'Edit', edit_product_path(@product) %> |
<%= link_to 'Back', products_path %>
get /products
Listing products
Title
Description
Image url
Price
Pragmatic Version Control
<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. dont use any version
control at all. Many others dont use it
well, and end up experiencing
time-consuming problems.
</p>
/images/svn.jpg
0.0
Show
Edit
Destroy
New product
get /products/1
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. dont use any version
control at all. Many others dont use it
well, and end up experiencing
time-consuming problems.
</p>
Image url:
/images/svn.jpg
Price:
0.0
Edit |
Back
get /products/new
rake test
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
Loaded suite C:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
.
Finished in 0.24 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
Loaded suite C:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
.......
Finished in 0.591 seconds.
7 tests, 10 assertions, 0 failures, 0 errors
edit app\views\products\show.html.erb
<p>
<b>Title:</b>
<%= @product.title %>
</p>
<p>
<b>Description:</b>
<%= @product.description %>
</p>
<p>
<b>Image url:</b>
<%= @product.image_url %>
</p>
<p>
<b>Price:</b>
<%= @product.price %>
</p>
<%= link_to 'Edit', edit_product_path(@product) %> |
<%= link_to 'Back', products_path %>
get /products/1
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. dont use any version
control at all. Many others dont use it
well, and end up experiencing
time-consuming problems.
</p>
Image url:
/images/svn.jpg
Price:
0.0
Edit |
Back
6.4 Iteration A3: Validate!
edit app\models\product.rb
class Product < ActiveRecord::Base
validates_presence_of :title, :description, :image_url
validates_numericality_of :price
validate :price_must_be_at_least_a_cent
validates_uniqueness_of :title
validates_format_of :image_url, :allow_blank => true,
:with => %r{\.(gif|jpg|png)$}i,
:message => 'must be a URL for GIF, JPG ' +
'or PNG image.'
protected
def price_must_be_at_least_a_cent
errors.add(:price, 'should be at least 0.01') if price.nil? ||
price < 0.00
end
end
get /products/new
post /products
get /products/new
post /products
product[image_url] => /images/utj.jpg
product[price] => wibble
product[description] => A true masterwork. Comparable to Kafka at
his funniest, or Marx during his slapstick
period. Move over, Tolstoy, there's a new
funster in town.
product[title] => Pragmatic Unit Testing
edit app\models\product.rb
class Product < ActiveRecord::Base
validates_presence_of :title, :description, :image_url
validates_numericality_of :price
validate :price_must_be_at_least_a_cent
validates_uniqueness_of :title
validates_format_of :image_url,
:with => %r{\.(gif|jpg|png)$}i,
:message => 'must be a URL for GIF, JPG ' +
'or PNG image.'
protected
def price_must_be_at_least_a_cent
errors.add(:price, 'should be at least 0.01') if price.nil? ||
price < 0.01
end
end
edit app\views\layouts\products.html.erb
6.5 Iteration A4: Making Prettier Listings
edit db\migrate\003_add_test_data.rb
class AddTestData < ActiveRecord::Migration
def self.up
Product.delete_all
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---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)
# . . .
end
def self.down
Product.delete_all
end
end
rake db:migrate
mv 003_add_test_data.rb 20100301000003_add_test_data.rb
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
== AddTestData: migrating ====================================================
== AddTestData: migrated (0.0450s) ===========================================
edit app\views\layouts\products.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Products: <%= controller.action_name %></title>
<%= stylesheet_link_tag 'scaffold', 'depot' %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
</head>
edit app\views\products\index.html.erb
<div id="product-list">
<h1>Listing products</h1>
<table>
<% @products.each do |product| %>
<tr class="<%= cycle('list-line-odd', 'list-line-even') %>">
<td>
<%= image_tag product.image_url, :class => 'list-image' %>
</td>
<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 %>
xcopy /i /f /y C:\cygwin\home\rubys\git\awdwr\data\images\* public\images\
C:\cygwin\home\rubys\git\awdwr\data\images\.htaccess -> C:\cygwin\home\rubys\git\awdwr\work\depot\public\images\.htaccess
C:\cygwin\home\rubys\git\awdwr\data\images\auto.jpg -> C:\cygwin\home\rubys\git\awdwr\work\depot\public\images\auto.jpg
C:\cygwin\home\rubys\git\awdwr\data\images\logo.png -> C:\cygwin\home\rubys\git\awdwr\work\depot\public\images\logo.png
C:\cygwin\home\rubys\git\awdwr\data\images\rails.png -> C:\cygwin\home\rubys\git\awdwr\work\depot\public\images\rails.png
C:\cygwin\home\rubys\git\awdwr\data\images\svn.jpg -> C:\cygwin\home\rubys\git\awdwr\work\depot\public\images\svn.jpg
C:\cygwin\home\rubys\git\awdwr\data\images\utc.jpg -> C:\cygwin\home\rubys\git\awdwr\work\depot\public\images\utc.jpg
6 File(s) copied
xcopy /i /f /y C:\cygwin\home\rubys\git\awdwr\data\depot.css public\stylesheets
C:\cygwin\home\rubys\git\awdwr\data\depot.css -> C:\cygwin\home\rubys\git\awdwr\work\depot\public\stylesheets\depot.css
1 File(s) copied
get /products
7.1 Iteration B1: Create the Catalog Listing
ruby script\rails generate controller store index
create app/controllers/store_controller.rb
invoke erb
create app/views/store
create app/views/store/index.html.erb
invoke test_unit
create test/functional/store_controller_test.rb
invoke helper
create app/helpers/store_helper.rb
invoke test_unit
create test/unit/helpers/store_helper_test.rb
get /store
Store#index
Find me in app/views/store/index.html.erb
edit app\controllers\store_controller.rb
class StoreController < ApplicationController
def index
@products = Product.find_products_for_sale
end
end
edit app\models\product.rb
class Product < ActiveRecord::Base
def self.find_products_for_sale
find(:all, :order => "title")
end
# validation stuff...
validates_presence_of :title, :description, :image_url
validates_numericality_of :price
validate :price_must_be_at_least_a_cent
validates_uniqueness_of :title
validates_format_of :image_url,
:with => %r{\.(gif|jpg|png)$}i,
:message => 'must be a URL for GIF, JPG ' +
'or PNG image.'
protected
def price_must_be_at_least_a_cent
errors.add(:price, 'should be at least 0.01') if price.nil? ||
price < 0.01
end
end
edit app\views\store\index.html.erb
<h1>Your Pragmatic Catalog</h1>
<% @products.each do |product| -%>
<div class="entry">
<%= image_tag(product.image_url) %>
<h3><%=h product.title %></h3>
<%=raw product.description %>
<div class="price-line">
<span class="price"><%= product.price %></span>
</div>
</div>
<% end %>
get /store
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
29.95
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
27.75
Pragmatic Version Control
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.
28.5
7.2 Iteration B2: Add a Page Layout
edit app\views\layouts\store.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Pragprog Books Online Store</title>
<%= stylesheet_link_tag "depot", :media => "all" %><!-- <label id="code.slt"/> -->
</head>
<body id="store">
<div id="banner">
<%= image_tag("logo.png") %>
<%= @page_title || "Pragmatic Bookshelf" %><!-- <label id="code.depot.e.title"/> -->
</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">
<%= yield :layout %><!-- <label id="code.depot.e.include"/> -->
</div>
</div>
</body>
</html>
edit public\stylesheets\depot.css
/* Styles for main page */
#banner {
background: #9c9;
padding-top: 10px;
padding-bottom: 10px;
border-bottom: 2px solid;
font: small-caps 40px/40px "Times New Roman", serif;
color: #282;
text-align: center;
}
#banner img {
float: left;
}
#columns {
background: #141;
}
#main {
margin-left: 13em;
padding-top: 4ex;
padding-left: 2em;
background: white;
}
#side {
float: left;
padding-top: 1em;
padding-left: 1em;
padding-bottom: 1em;
width: 12em;
background: #141;
}
#side a {
color: #bfb;
font-size: small;
}
get /store
Pragmatic Bookshelf
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
29.95
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
27.75
Pragmatic Version Control
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.
28.5
7.3 Iteration B3: Use a Helper to Format the Price
edit app\views\store\index.html.erb
<h1>Your Pragmatic Catalog</h1>
<% @products.each do |product| -%>
<div class="entry">
<%= image_tag(product.image_url) %>
<h3><%=h product.title %></h3>
<%=raw product.description %>
<div class="price-line">
<span class="price"><%= number_to_currency(product.price) %></span>
</div>
</div>
<% end %>
get /store
Pragmatic Bookshelf
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
$29.95
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
$27.75
Pragmatic Version Control
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.
$28.50
7.4 Iteration B4: Linking to the Cart
edit app\views\store\index.html.erb
<%= button_to 'Add to Cart' %>
edit public\stylesheets\depot.css
#store .entry form, #store .entry form div {
display: inline;
}
get /store
Pragmatic Bookshelf
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
8.1 Sessions
rake db:sessions:create
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
invoke active_record
create db/migrate/20100225154844_add_sessions_table.rb
rake db:migrate
mv 20100225154844_add_sessions_table.rb 20100301000004_add_sessions_table.rb
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
== AddSessionsTable: migrating ===============================================
-- create_table(:sessions)
-> 0.0020s
-- add_index(:sessions, :session_id)
-> 0.0010s
-- add_index(:sessions, :updated_at)
-> 0.0000s
== AddSessionsTable: migrated (0.0030s) ======================================
sqlite3 db\development.sqlite3 .schema
CREATE TABLE "products" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(255), "description" text, "image_url" varchar(255), "created_at" datetime, "updated_at" datetime, "price" decimal(8,2) DEFAULT 0);
CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL);
CREATE TABLE "sessions" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "session_id" varchar(255) NOT NULL, "data" text, "created_at" datetime, "updated_at" datetime);
CREATE INDEX "index_sessions_on_session_id" ON "sessions" ("session_id");
CREATE INDEX "index_sessions_on_updated_at" ON "sessions" ("updated_at");
CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version");
edit config\initializers\session_store.rb
# Be sure to restart your server when you modify this file.
# Your secret key for verifying cookie session data integrity.
# If you change this key, all old sessions will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
ActionController::Base.session = {
:key => '_depot_session',
:secret => '44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac'
}
# Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
# (create the session table with "rake db:sessions:create")
ActionController::Base.session_store = :active_record_store
Restart the server.
edit app\controllers\application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
end
edit app\controllers\store_controller.rb
private
def find_cart
session[:cart] ||= Cart.new
end
8.2 Iteration C1: Creating a Cart
edit app\models\cart.rb
class Cart
attr_reader :items # <wtf linkend="wtf.attr.accessor">attr_reader</wtf>
def initialize
@items = []
end
def add_product(product)
@items << product
end
end
edit app\views\store\index.html.erb
<%= button_to 'Add to Cart', :action => 'add_to_cart', :id => product %>
edit app\controllers\store_controller.rb
def add_to_cart
product = Product.find(params[:id]) # <label id="code.depot.f.find"/>
@cart = find_cart # <label id="code.depot.f.find2"/>
@cart.add_product(product) # <label id="code.depot.f.add"/>
end
get /store/add_to_cart/2
Template is missing
Missing template store/add_to_cart with {:locale=>[:en], :formats=>[:html]} in view paths "C:/cygwin/home/rubys/git/awdwr/work/depot/app/views"
edit app\views\store\add_to_cart.html.erb
<h2>Your Pragmatic Cart</h2>
<ul>
<% for item in @cart.items %>
<li><%=h item.title %></li>
<% end %>
</ul>
get /store/add_to_cart/2
Pragmatic Bookshelf
Your Pragmatic Cart
Pragmatic Project Automation
get /store/add_to_cart/3
Pragmatic Bookshelf
Your Pragmatic Cart
Pragmatic Project Automation
Pragmatic Version Control
8.3 Iteration C2: Creating a Smarter Cart
edit app\models\cart_item.rb
class CartItem
attr_reader :product, :quantity
def initialize(product)
@product = product
@quantity = 1
end
def increment_quantity
@quantity += 1
end
def title
@product.title
end
def price
@product.price * @quantity
end
end
edit app\models\cart.rb
def add_product(product)
current_item = @items.find {|item| item.product == product}
if current_item
current_item.increment_quantity
else
@items << CartItem.new(product)
end
end
edit app\views\store\add_to_cart.html.erb
<h2>Your Pragmatic Cart</h2>
<ul>
<% for item in @cart.items %>
<li><%= item.quantity %> × <%= item.title %></li>
<% end %>
</ul>
get /store/add_to_cart/2
NoMethodError
in StoreController#add_to_cart
undefined method `product' for #<Product:0x4ac3670>
Rails.root: C:/cygwin/home/rubys/git/awdwr/work/depot
Application Trace |
Framework Trace |
Full Trace
app/models/cart.rb:10:in `add_product'
app/models/cart.rb:10:in `each'
app/models/cart.rb:10:in `find'
app/models/cart.rb:10:in `add_product'
app/controllers/store_controller.rb:11:in `add_to_cart'
C:/cygwin/home/rubys/git/rails/activemodel/lib/active_model/attribute_methods.rb:343:in `method_missing'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/attribute_methods.rb:36:in `method_missing'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/attribute_methods.rb:34:in `send'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/attribute_methods.rb:34:in `method_missing'
C:/cygwin/home/rubys/git/rails/activemodel/lib/active_model/attribute_methods.rb:96:in `find'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/base.rb:44:in `send_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/base.rb:44:in `send_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/base.rb:145:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/callbacks.rb:18:in `process_action'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:433:in `_run__849683412__process_action__746879535__callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:403:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:403:in `_run_process_action_callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `run_callbacks'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/callbacks.rb:17:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rendering.rb:11:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/compatibility.rb:64:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/instrumentation.rb:29:in `process_action'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/notifications/instrumenter.rb:18:in `instrument'
C:1:in `__send__'
C:1:in `instrument'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/instrumentation.rb:28:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rescue.rb:8:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/base.rb:115:in `process'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal.rb:72:in `dispatch'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rack_delegation.rb:19:in `dispatch'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal.rb:97:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/routing/route_set.rb:28:in `call'
rack-mount (0.5.2) lib/rack/mount/recognition/route_set.rb:75:in `call'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:99:in `recognize'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:76:in `optimized_each'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:98:in `recognize'
rack-mount (0.5.2) lib/rack/mount/recognition/route_set.rb:66:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/routing/route_set.rb:419:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:29:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:34:in `cache'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:9:in `cache'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:28:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:365:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/head.rb:14:in `call'
rack (1.1.0) lib/rack/methodoverride.rb:24:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/params_parser.rb:20:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/flash.rb:167:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb:150:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/cookies.rb:205:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/callbacks.rb:46:in `call'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:409:in `_run_call_callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `run_callbacks'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/callbacks.rb:44:in `call'
rack (1.1.0) lib/rack/sendfile.rb:105:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/show_exceptions.rb:62:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/rack/logger.rb:13:in `call'
rack (1.1.0) lib/rack/runtime.rb:17:in `call'
rack (1.1.0) lib/rack/lock.rb:11:in `call'
rack (1.1.0) lib/rack/lock.rb:11:in `synchronize'
rack (1.1.0) lib/rack/lock.rb:11:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/static.rb:30:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:95:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:41:in `send'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:41:in `method_missing'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/rack/log_tailer.rb:15:in `call'
rack (1.1.0) lib/rack/content_length.rb:13:in `call'
rack (1.1.0) lib/rack/handler/webrick.rb:48:in `service'
C:/ruby/lib/ruby/1.8/webrick/httpserver.rb:104:in `service'
C:/ruby/lib/ruby/1.8/webrick/httpserver.rb:65:in `run'
C:/ruby/lib/ruby/1.8/webrick/server.rb:173:in `start_thread'
C:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start_thread'
C:/ruby/lib/ruby/1.8/webrick/server.rb:95:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `each'
C:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:23:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:82:in `start'
rack (1.1.0) lib/rack/handler/webrick.rb:14:in `run'
rack (1.1.0) lib/rack/server.rb:155:in `start'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/commands/server.rb:57:in `start'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/commands.rb:42
script/rails:9:in `require'
script/rails:9
C:/cygwin/home/rubys/git/rails/activemodel/lib/active_model/attribute_methods.rb:343:in `method_missing'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/attribute_methods.rb:36:in `method_missing'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/attribute_methods.rb:34:in `send'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/attribute_methods.rb:34:in `method_missing'
app/models/cart.rb:10:in `add_product'
C:/cygwin/home/rubys/git/rails/activemodel/lib/active_model/attribute_methods.rb:96:in `find'
app/models/cart.rb:10:in `each'
app/models/cart.rb:10:in `find'
app/models/cart.rb:10:in `add_product'
app/controllers/store_controller.rb:11:in `add_to_cart'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/base.rb:44:in `send_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/base.rb:44:in `send_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/base.rb:145:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/callbacks.rb:18:in `process_action'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:433:in `_run__849683412__process_action__746879535__callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:403:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:403:in `_run_process_action_callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `run_callbacks'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/callbacks.rb:17:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rendering.rb:11:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/compatibility.rb:64:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/instrumentation.rb:29:in `process_action'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/notifications/instrumenter.rb:18:in `instrument'
C:1:in `__send__'
C:1:in `instrument'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/instrumentation.rb:28:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rescue.rb:8:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/base.rb:115:in `process'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal.rb:72:in `dispatch'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rack_delegation.rb:19:in `dispatch'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal.rb:97:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/routing/route_set.rb:28:in `call'
rack-mount (0.5.2) lib/rack/mount/recognition/route_set.rb:75:in `call'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:99:in `recognize'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:76:in `optimized_each'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:98:in `recognize'
rack-mount (0.5.2) lib/rack/mount/recognition/route_set.rb:66:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/routing/route_set.rb:419:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:29:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:34:in `cache'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:9:in `cache'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:28:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:365:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/head.rb:14:in `call'
rack (1.1.0) lib/rack/methodoverride.rb:24:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/params_parser.rb:20:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/flash.rb:167:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb:150:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/cookies.rb:205:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/callbacks.rb:46:in `call'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:409:in `_run_call_callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `run_callbacks'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/callbacks.rb:44:in `call'
rack (1.1.0) lib/rack/sendfile.rb:105:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/show_exceptions.rb:62:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/rack/logger.rb:13:in `call'
rack (1.1.0) lib/rack/runtime.rb:17:in `call'
rack (1.1.0) lib/rack/lock.rb:11:in `call'
rack (1.1.0) lib/rack/lock.rb:11:in `synchronize'
rack (1.1.0) lib/rack/lock.rb:11:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/static.rb:30:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:95:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:41:in `send'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:41:in `method_missing'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/rack/log_tailer.rb:15:in `call'
rack (1.1.0) lib/rack/content_length.rb:13:in `call'
rack (1.1.0) lib/rack/handler/webrick.rb:48:in `service'
C:/ruby/lib/ruby/1.8/webrick/httpserver.rb:104:in `service'
C:/ruby/lib/ruby/1.8/webrick/httpserver.rb:65:in `run'
C:/ruby/lib/ruby/1.8/webrick/server.rb:173:in `start_thread'
C:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start_thread'
C:/ruby/lib/ruby/1.8/webrick/server.rb:95:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `each'
C:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:23:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:82:in `start'
rack (1.1.0) lib/rack/handler/webrick.rb:14:in `run'
rack (1.1.0) lib/rack/server.rb:155:in `start'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/commands/server.rb:57:in `start'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/commands.rb:42
script/rails:9:in `require'
script/rails:9
Request
Parameters :
{"id"=>"2"}
Show session dump
cart: #<Cart:0x4ac3718 @items=[#<Product id: 2, title: "Pragmatic Project Automation", description: "<p>\n <em>Pragmatic Project Automation</em> sh...", image_url: "/images/auto.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46e64f8,'0.2995E2',8(8)>>, #<Product id: 3, title: "Pragmatic Version Control", description: "<p>\n This book is a recipe-based approach t...", image_url: "/images/svn.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46e5eb0,'0.285E2',8(8)>>]>
Show env dump
GATEWAY_INTERFACE: "CGI/1.1"
HTTP_ACCEPT: "text/html"
HTTP_COOKIE: "_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly"
HTTP_HOST: "localhost:3000"
HTTP_VERSION: "HTTP/1.1"
PATH_INFO: "/store/add_to_cart/2"
QUERY_STRING: ""
REMOTE_ADDR: "127.0.0.1"
REMOTE_HOST: "rubix4"
REQUEST_METHOD: "GET"
REQUEST_PATH: "/"
REQUEST_URI: "http://localhost:3000/store/add_to_cart/2"
SCRIPT_NAME: ""
SERVER_NAME: "localhost"
SERVER_PORT: "3000"
SERVER_PROTOCOL: "HTTP/1.1"
SERVER_SOFTWARE: "WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)"
action_controller.instance: #<StoreController:0x49872f0 @_params={"action"=>"add_to_cart", "id"=>"2", "controller"=>"store"}, @_formats=[:html], @cart=#<Cart:0x4ac3718 @items=[#<Product id: 2, title: "Pragmatic Project Automation", description: "<p>\n <em>Pragmatic Project Automation</em> sh...", image_url: "/images/auto.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46e35a0,'0.2995E2',8(8)>>, #<Product id: 3, title: "Pragmatic Version Control", description: "<p>\n This book is a recipe-based approach t...", image_url: "/images/svn.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46e1e78,'0.285E2',8(8)>>]>, @_response_body=nil, @_response=#<ActionDispatch::Response:0x4987128 @etag=nil, @sending_file=false, @length=0, @cache_control={}, @cookie=[], @body=[], @header={}, @block=nil, @writer=#<Proc:0x05e42698@C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/http/response.rb:42>, @status=200, @request=#<ActionDispatch::Request:0x4987140 @filtered_parameters={"action"=>"add_to_cart", "id"=>"2", "controller"=>"store"}, @env={"action_dispatch.request.formats"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "action_dispatch.request.parameters"=>{"action"=>"add_to_cart", "id"=>"2", "controller"=>"store"}, "rack.session.record"=>#<ActiveRecord::SessionStore::Session id: 1, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7BiIJY2FydG86CUNhcnQGOgtAaXRlbXNbB286DFByb2R1Y3Q...", created_at: "2010-02-25 15:48:58", updated_at: "2010-02-25 15:48:59">, "rack.session"=>{"cart"=>#<Cart:0x4ac3718 @items=[#<Product id: 2, title: "Pragmatic Project Automation", description: "<p>\n <em>Pragmatic Project Automation</em> sh...", image_url: "/images/auto.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46e0420,'0.2995E2',8(8)>>, #<Product id: 3, title: "Pragmatic Version Control", description: "<p>\n This book is a recipe-based approach t...", image_url: "/images/svn.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46dfd60,'0.285E2',8(8)>>]>}, "HTTP_HOST"=>"localhost:3000", "HTTP_ACCEPT"=>"text/html", "SERVER_NAME"=>"localhost", "rack.request.cookie_hash"=>{"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}, "REQUEST_PATH"=>"/", "rack.url_scheme"=>"http", "REMOTE_HOST"=>"rubix4", "action_dispatch.request.query_parameters"=>{}, "rack.errors"=>#<IO:0x2feda90>, "SERVER_PROTOCOL"=>"HTTP/1.1", "action_dispatch.request.accepts"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "rack.version"=>[1, 1], "rack.run_once"=>false, "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)", "REMOTE_ADDR"=>"127.0.0.1", "PATH_INFO"=>"/store/add_to_cart/2", "action_dispatch.request.path_parameters"=>{:controller=>"store", :action=>"add_to_cart", :id=>"2"}, "rack.request.cookie_string"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "SCRIPT_NAME"=>"", "action_dispatch.parameter_filter"=>[:password], "HTTP_VERSION"=>"HTTP/1.1", "rack.multithread"=>false, "HTTP_COOKIE"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "action_dispatch.request.request_parameters"=>{}, "rack.multiprocess"=>false, "REQUEST_URI"=>"http://localhost:3000/store/add_to_cart/2", "rack.request.query_hash"=>{}, "SERVER_PORT"=>"3000", "action_controller.instance"=>#<StoreController:0x49872f0 ...>, "rack.session.options"=>{:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}, "REQUEST_METHOD"=>"GET", "rack.request.query_string"=>"", "action_dispatch.request.content_type"=>nil, "rack.input"=>#<StringIO:0x5cedc28>, "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1"}>, @blank=false>, @_view_context=#<Class>, @_request=#<ActionDispatch::Request:0x4987140 @filtered_parameters={"action"=>"add_to_cart", "id"=>"2", "controller"=>"store"}, @env={"action_dispatch.request.formats"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "action_dispatch.request.parameters"=>{"action"=>"add_to_cart", "id"=>"2", "controller"=>"store"}, "rack.session.record"=>#<ActiveRecord::SessionStore::Session id: 1, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7BiIJY2FydG86CUNhcnQGOgtAaXRlbXNbB286DFByb2R1Y3Q...", created_at: "2010-02-25 15:48:58", updated_at: "2010-02-25 15:48:59">, "rack.session"=>{"cart"=>#<Cart:0x4ac3718 @items=[#<Product id: 2, title: "Pragmatic Project Automation", description: "<p>\n <em>Pragmatic Project Automation</em> sh...", image_url: "/images/auto.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46db140,'0.2995E2',8(8)>>, #<Product id: 3, title: "Pragmatic Version Control", description: "<p>\n This book is a recipe-based approach t...", image_url: "/images/svn.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46da0a8,'0.285E2',8(8)>>]>}, "HTTP_HOST"=>"localhost:3000", "HTTP_ACCEPT"=>"text/html", "SERVER_NAME"=>"localhost", "rack.request.cookie_hash"=>{"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}, "REQUEST_PATH"=>"/", "rack.url_scheme"=>"http", "REMOTE_HOST"=>"rubix4", "action_dispatch.request.query_parameters"=>{}, "rack.errors"=>#<IO:0x2feda90>, "SERVER_PROTOCOL"=>"HTTP/1.1", "action_dispatch.request.accepts"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "rack.version"=>[1, 1], "rack.run_once"=>false, "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)", "REMOTE_ADDR"=>"127.0.0.1", "PATH_INFO"=>"/store/add_to_cart/2", "action_dispatch.request.path_parameters"=>{:controller=>"store", :action=>"add_to_cart", :id=>"2"}, "rack.request.cookie_string"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "SCRIPT_NAME"=>"", "action_dispatch.parameter_filter"=>[:password], "HTTP_VERSION"=>"HTTP/1.1", "rack.multithread"=>false, "HTTP_COOKIE"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "action_dispatch.request.request_parameters"=>{}, "rack.multiprocess"=>false, "REQUEST_URI"=>"http://localhost:3000/store/add_to_cart/2", "rack.request.query_hash"=>{}, "SERVER_PORT"=>"3000", "action_controller.instance"=>#<StoreController:0x49872f0 ...>, "rack.session.options"=>{:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}, "REQUEST_METHOD"=>"GET", "rack.request.query_string"=>"", "action_dispatch.request.content_type"=>nil, "rack.input"=>#<StringIO:0x5cedc28>, "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1"}>, @_env={"action_dispatch.request.formats"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "action_dispatch.request.parameters"=>{"action"=>"add_to_cart", "id"=>"2", "controller"=>"store"}, "rack.session.record"=>#<ActiveRecord::SessionStore::Session id: 1, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7BiIJY2FydG86CUNhcnQGOgtAaXRlbXNbB286DFByb2R1Y3Q...", created_at: "2010-02-25 15:48:58", updated_at: "2010-02-25 15:48:59">, "rack.session"=>{"cart"=>#<Cart:0x4ac3718 @items=[#<Product id: 2, title: "Pragmatic Project Automation", description: "<p>\n <em>Pragmatic Project Automation</em> sh...", image_url: "/images/auto.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46d3da8,'0.2995E2',8(8)>>, #<Product id: 3, title: "Pragmatic Version Control", description: "<p>\n This book is a recipe-based approach t...", image_url: "/images/svn.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46d36e8,'0.285E2',8(8)>>]>}, "HTTP_HOST"=>"localhost:3000", "HTTP_ACCEPT"=>"text/html", "SERVER_NAME"=>"localhost", "rack.request.cookie_hash"=>{"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}, "REQUEST_PATH"=>"/", "rack.url_scheme"=>"http", "REMOTE_HOST"=>"rubix4", "action_dispatch.request.query_parameters"=>{}, "rack.errors"=>#<IO:0x2feda90>, "SERVER_PROTOCOL"=>"HTTP/1.1", "action_dispatch.request.accepts"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "rack.version"=>[1, 1], "rack.run_once"=>false, "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)", "REMOTE_ADDR"=>"127.0.0.1", "PATH_INFO"=>"/store/add_to_cart/2", "action_dispatch.request.path_parameters"=>{:controller=>"store", :action=>"add_to_cart", :id=>"2"}, "rack.request.cookie_string"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "SCRIPT_NAME"=>"", "action_dispatch.parameter_filter"=>[:password], "HTTP_VERSION"=>"HTTP/1.1", "rack.multithread"=>false, "HTTP_COOKIE"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "action_dispatch.request.request_parameters"=>{}, "rack.multiprocess"=>false, "REQUEST_URI"=>"http://localhost:3000/store/add_to_cart/2", "rack.request.query_hash"=>{}, "SERVER_PORT"=>"3000", "action_controller.instance"=>#<StoreController:0x49872f0 ...>, "rack.session.options"=>{:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}, "REQUEST_METHOD"=>"GET", "rack.request.query_string"=>"", "action_dispatch.request.content_type"=>nil, "rack.input"=>#<StringIO:0x5cedc28>, "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1"}, @_headers={}, @_action_name="add_to_cart", @template=#<Class>>
action_dispatch.parameter_filter: [:password]
action_dispatch.request.accepts: [#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>]
action_dispatch.request.content_type: nil
action_dispatch.request.formats: [#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>]
action_dispatch.request.parameters: {"action"=>"add_to_cart", "id"=>"2", "controller"=>"store"}
action_dispatch.request.path_parameters: {:controller=>"store", :action=>"add_to_cart", :id=>"2"}
action_dispatch.request.query_parameters: {}
action_dispatch.request.request_parameters: {}
rack.errors: #<IO:0x2feda90>
rack.input: #<StringIO:0x5cedc28>
rack.multiprocess: false
rack.multithread: false
rack.request.cookie_hash: {"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}
rack.request.cookie_string: "_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly"
rack.request.query_hash: {}
rack.request.query_string: ""
rack.run_once: false
rack.session: {"cart"=>#<Cart:0x4ac3718 @items=[#<Product id: 2, title: "Pragmatic Project Automation", description: "<p>\n <em>Pragmatic Project Automation</em> sh...", image_url: "/images/auto.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46cd970,'0.2995E2',8(8)>>, #<Product id: 3, title: "Pragmatic Version Control", description: "<p>\n This book is a recipe-based approach t...", image_url: "/images/svn.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:46cc0b0,'0.285E2',8(8)>>]>}
rack.session.options: {:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}
rack.session.record: #<ActiveRecord::SessionStore::Session id: 1, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7BiIJY2FydG86CUNhcnQGOgtAaXRlbXNbB286DFByb2R1Y3Q...", created_at: "2010-02-25 15:48:58", updated_at: "2010-02-25 15:48:59">
rack.url_scheme: "http"
rack.version: [1, 1]
Response
Headers :
None
rake db:sessions:clear
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
get /store/add_to_cart/2
Pragmatic Bookshelf
Your Pragmatic Cart
1 × Pragmatic Project Automation
get /store/add_to_cart/2
Pragmatic Bookshelf
Your Pragmatic Cart
2 × Pragmatic Project Automation
get /store/add_to_cart/3
Pragmatic Bookshelf
Your Pragmatic Cart
2 × Pragmatic Project Automation
1 × Pragmatic Version Control
get /store/add_to_cart/wibble
ActiveRecord::RecordNotFound
in StoreController#add_to_cart
Couldn't find Product with ID=wibble
Rails.root: C:/cygwin/home/rubys/git/awdwr/work/depot
Application Trace |
Framework Trace |
Full Trace
app/controllers/store_controller.rb:9:in `add_to_cart'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/relation/finder_methods.rb:265:in `find_one'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/relation/finder_methods.rb:252:in `find_with_ids'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/relation/finder_methods.rb:99:in `find'
C:1:in `__send__'
C:1:in `find'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/base.rb:44:in `send_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/base.rb:44:in `send_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/base.rb:145:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/callbacks.rb:18:in `process_action'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:433:in `_run__849683412__process_action__746879535__callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:403:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:403:in `_run_process_action_callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `run_callbacks'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/callbacks.rb:17:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rendering.rb:11:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/compatibility.rb:64:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/instrumentation.rb:29:in `process_action'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/notifications/instrumenter.rb:18:in `instrument'
C:1:in `__send__'
C:1:in `instrument'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/instrumentation.rb:28:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rescue.rb:8:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/base.rb:115:in `process'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal.rb:72:in `dispatch'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rack_delegation.rb:19:in `dispatch'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal.rb:97:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/routing/route_set.rb:28:in `call'
rack-mount (0.5.2) lib/rack/mount/recognition/route_set.rb:75:in `call'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:99:in `recognize'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:76:in `optimized_each'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:98:in `recognize'
rack-mount (0.5.2) lib/rack/mount/recognition/route_set.rb:66:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/routing/route_set.rb:419:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:29:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:34:in `cache'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:9:in `cache'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:28:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:365:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/head.rb:14:in `call'
rack (1.1.0) lib/rack/methodoverride.rb:24:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/params_parser.rb:20:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/flash.rb:167:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb:150:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/cookies.rb:205:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/callbacks.rb:46:in `call'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:409:in `_run_call_callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `run_callbacks'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/callbacks.rb:44:in `call'
rack (1.1.0) lib/rack/sendfile.rb:105:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/show_exceptions.rb:62:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/rack/logger.rb:13:in `call'
rack (1.1.0) lib/rack/runtime.rb:17:in `call'
rack (1.1.0) lib/rack/lock.rb:11:in `call'
rack (1.1.0) lib/rack/lock.rb:11:in `synchronize'
rack (1.1.0) lib/rack/lock.rb:11:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/static.rb:30:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:95:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:41:in `send'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:41:in `method_missing'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/rack/log_tailer.rb:15:in `call'
rack (1.1.0) lib/rack/content_length.rb:13:in `call'
rack (1.1.0) lib/rack/handler/webrick.rb:48:in `service'
C:/ruby/lib/ruby/1.8/webrick/httpserver.rb:104:in `service'
C:/ruby/lib/ruby/1.8/webrick/httpserver.rb:65:in `run'
C:/ruby/lib/ruby/1.8/webrick/server.rb:173:in `start_thread'
C:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start_thread'
C:/ruby/lib/ruby/1.8/webrick/server.rb:95:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `each'
C:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:23:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:82:in `start'
rack (1.1.0) lib/rack/handler/webrick.rb:14:in `run'
rack (1.1.0) lib/rack/server.rb:155:in `start'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/commands/server.rb:57:in `start'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/commands.rb:42
script/rails:9:in `require'
script/rails:9
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/relation/finder_methods.rb:265:in `find_one'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/relation/finder_methods.rb:252:in `find_with_ids'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/relation/finder_methods.rb:99:in `find'
C:1:in `__send__'
C:1:in `find'
app/controllers/store_controller.rb:9:in `add_to_cart'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/base.rb:44:in `send_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/base.rb:44:in `send_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/base.rb:145:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/callbacks.rb:18:in `process_action'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:433:in `_run__849683412__process_action__746879535__callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:403:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:403:in `_run_process_action_callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `run_callbacks'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/callbacks.rb:17:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rendering.rb:11:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/compatibility.rb:64:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/instrumentation.rb:29:in `process_action'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/notifications/instrumenter.rb:18:in `instrument'
C:1:in `__send__'
C:1:in `instrument'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/instrumentation.rb:28:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rescue.rb:8:in `process_action'
C:/cygwin/home/rubys/git/rails/actionpack/lib/abstract_controller/base.rb:115:in `process'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal.rb:72:in `dispatch'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal/rack_delegation.rb:19:in `dispatch'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_controller/metal.rb:97:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/routing/route_set.rb:28:in `call'
rack-mount (0.5.2) lib/rack/mount/recognition/route_set.rb:75:in `call'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:99:in `recognize'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:76:in `optimized_each'
rack-mount (0.5.2) lib/rack/mount/recognition/code_generation.rb:98:in `recognize'
rack-mount (0.5.2) lib/rack/mount/recognition/route_set.rb:66:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/routing/route_set.rb:419:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:29:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:34:in `cache'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:9:in `cache'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/query_cache.rb:28:in `call'
C:/cygwin/home/rubys/git/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:365:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/head.rb:14:in `call'
rack (1.1.0) lib/rack/methodoverride.rb:24:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/params_parser.rb:20:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/flash.rb:167:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb:150:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/cookies.rb:205:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/callbacks.rb:46:in `call'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:409:in `_run_call_callbacks'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `send'
C:/cygwin/home/rubys/git/rails/activesupport/lib/active_support/callbacks.rb:88:in `run_callbacks'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/callbacks.rb:44:in `call'
rack (1.1.0) lib/rack/sendfile.rb:105:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/show_exceptions.rb:62:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/rack/logger.rb:13:in `call'
rack (1.1.0) lib/rack/runtime.rb:17:in `call'
rack (1.1.0) lib/rack/lock.rb:11:in `call'
rack (1.1.0) lib/rack/lock.rb:11:in `synchronize'
rack (1.1.0) lib/rack/lock.rb:11:in `call'
C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/static.rb:30:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:95:in `call'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:41:in `send'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/application.rb:41:in `method_missing'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/rack/log_tailer.rb:15:in `call'
rack (1.1.0) lib/rack/content_length.rb:13:in `call'
rack (1.1.0) lib/rack/handler/webrick.rb:48:in `service'
C:/ruby/lib/ruby/1.8/webrick/httpserver.rb:104:in `service'
C:/ruby/lib/ruby/1.8/webrick/httpserver.rb:65:in `run'
C:/ruby/lib/ruby/1.8/webrick/server.rb:173:in `start_thread'
C:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start_thread'
C:/ruby/lib/ruby/1.8/webrick/server.rb:95:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `each'
C:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:23:in `start'
C:/ruby/lib/ruby/1.8/webrick/server.rb:82:in `start'
rack (1.1.0) lib/rack/handler/webrick.rb:14:in `run'
rack (1.1.0) lib/rack/server.rb:155:in `start'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/commands/server.rb:57:in `start'
C:/cygwin/home/rubys/git/rails/railties/lib/rails/commands.rb:42
script/rails:9:in `require'
script/rails:9
Request
Parameters :
{"id"=>"wibble"}
Show session dump
cart: #<Cart:0x5f55450 @items=[#<CartItem:0x5f553d8 @product=#<Product id: 2, title: "Pragmatic Project Automation", description: "<p>\n <em>Pragmatic Project Automation</em> sh...", image_url: "/images/auto.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:5dfee38,'0.2995E2',8(8)>>, @quantity=2>, #<CartItem:0x5f550d8 @product=#<Product id: 3, title: "Pragmatic Version Control", description: "<p>\n This book is a recipe-based approach t...", image_url: "/images/svn.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:5dfe880,'0.285E2',8(8)>>, @quantity=1>]>
Show env dump
GATEWAY_INTERFACE: "CGI/1.1"
HTTP_ACCEPT: "text/html"
HTTP_COOKIE: "_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly"
HTTP_HOST: "localhost:3000"
HTTP_VERSION: "HTTP/1.1"
PATH_INFO: "/store/add_to_cart/wibble"
QUERY_STRING: ""
REMOTE_ADDR: "127.0.0.1"
REMOTE_HOST: "rubix4"
REQUEST_METHOD: "GET"
REQUEST_PATH: "/"
REQUEST_URI: "http://localhost:3000/store/add_to_cart/wibble"
SCRIPT_NAME: ""
SERVER_NAME: "localhost"
SERVER_PORT: "3000"
SERVER_PROTOCOL: "HTTP/1.1"
SERVER_SOFTWARE: "WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)"
action_controller.instance: #<StoreController:0x5ede578 @_params={"action"=>"add_to_cart", "id"=>"wibble", "controller"=>"store"}, @_formats=[:html], @_response_body=nil, @_response=#<ActionDispatch::Response:0x5ede500 @etag=nil, @sending_file=false, @length=0, @cache_control={}, @cookie=[], @body=[], @header={}, @block=nil, @writer=#<Proc:0x05e42698@C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/http/response.rb:42>, @status=200, @request=#<ActionDispatch::Request:0x5ede518 @filtered_parameters={"action"=>"add_to_cart", "id"=>"wibble", "controller"=>"store"}, @env={"action_dispatch.request.formats"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "action_dispatch.request.parameters"=>{"action"=>"add_to_cart", "id"=>"wibble", "controller"=>"store"}, "rack.session.record"=>#<ActiveRecord::SessionStore::Session id: 2, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7BiIJY2FydG86CUNhcnQGOgtAaXRlbXNbB286DUNhcnRJdGV...", created_at: "2010-02-25 15:49:06", updated_at: "2010-02-25 15:49:06">, "rack.session"=>{"cart"=>#<Cart:0x5f55450 @items=[#<CartItem:0x5f553d8 @product=#<Product id: 2, title: "Pragmatic Project Automation", description: "<p>\n <em>Pragmatic Project Automation</em> sh...", image_url: "/images/auto.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:5dfc330,'0.2995E2',8(8)>>, @quantity=2>, #<CartItem:0x5f550d8 @product=#<Product id: 3, title: "Pragmatic Version Control", description: "<p>\n This book is a recipe-based approach t...", image_url: "/images/svn.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:5dfbb20,'0.285E2',8(8)>>, @quantity=1>]>}, "HTTP_HOST"=>"localhost:3000", "HTTP_ACCEPT"=>"text/html", "SERVER_NAME"=>"localhost", "rack.request.cookie_hash"=>{"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}, "REQUEST_PATH"=>"/", "rack.url_scheme"=>"http", "REMOTE_HOST"=>"rubix4", "action_dispatch.request.query_parameters"=>{}, "rack.errors"=>#<IO:0x2feda90>, "SERVER_PROTOCOL"=>"HTTP/1.1", "action_dispatch.request.accepts"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "rack.version"=>[1, 1], "rack.run_once"=>false, "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)", "REMOTE_ADDR"=>"127.0.0.1", "PATH_INFO"=>"/store/add_to_cart/wibble", "action_dispatch.request.path_parameters"=>{:controller=>"store", :action=>"add_to_cart", :id=>"wibble"}, "rack.request.cookie_string"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "SCRIPT_NAME"=>"", "action_dispatch.parameter_filter"=>[:password], "HTTP_VERSION"=>"HTTP/1.1", "rack.multithread"=>false, "HTTP_COOKIE"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "action_dispatch.request.request_parameters"=>{}, "rack.multiprocess"=>false, "REQUEST_URI"=>"http://localhost:3000/store/add_to_cart/wibble", "rack.request.query_hash"=>{}, "SERVER_PORT"=>"3000", "action_controller.instance"=>#<StoreController:0x5ede578 ...>, "rack.session.options"=>{:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}, "REQUEST_METHOD"=>"GET", "rack.request.query_string"=>"", "action_dispatch.request.content_type"=>nil, "rack.input"=>#<StringIO:0x5fced70>, "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1"}>, @blank=false>, @_view_context=#<Class>, @_request=#<ActionDispatch::Request:0x5ede518 @filtered_parameters={"action"=>"add_to_cart", "id"=>"wibble", "controller"=>"store"}, @env={"action_dispatch.request.formats"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "action_dispatch.request.parameters"=>{"action"=>"add_to_cart", "id"=>"wibble", "controller"=>"store"}, "rack.session.record"=>#<ActiveRecord::SessionStore::Session id: 2, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7BiIJY2FydG86CUNhcnQGOgtAaXRlbXNbB286DUNhcnRJdGV...", created_at: "2010-02-25 15:49:06", updated_at: "2010-02-25 15:49:06">, "rack.session"=>{"cart"=>#<Cart:0x5f55450 @items=[#<CartItem:0x5f553d8 @product=#<Product id: 2, title: "Pragmatic Project Automation", description: "<p>\n <em>Pragmatic Project Automation</em> sh...", image_url: "/images/auto.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:5df85c8,'0.2995E2',8(8)>>, @quantity=2>, #<CartItem:0x5f550d8 @product=#<Product id: 3, title: "Pragmatic Version Control", description: "<p>\n This book is a recipe-based approach t...", image_url: "/images/svn.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:5df79b0,'0.285E2',8(8)>>, @quantity=1>]>}, "HTTP_HOST"=>"localhost:3000", "HTTP_ACCEPT"=>"text/html", "SERVER_NAME"=>"localhost", "rack.request.cookie_hash"=>{"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}, "REQUEST_PATH"=>"/", "rack.url_scheme"=>"http", "REMOTE_HOST"=>"rubix4", "action_dispatch.request.query_parameters"=>{}, "rack.errors"=>#<IO:0x2feda90>, "SERVER_PROTOCOL"=>"HTTP/1.1", "action_dispatch.request.accepts"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "rack.version"=>[1, 1], "rack.run_once"=>false, "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)", "REMOTE_ADDR"=>"127.0.0.1", "PATH_INFO"=>"/store/add_to_cart/wibble", "action_dispatch.request.path_parameters"=>{:controller=>"store", :action=>"add_to_cart", :id=>"wibble"}, "rack.request.cookie_string"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "SCRIPT_NAME"=>"", "action_dispatch.parameter_filter"=>[:password], "HTTP_VERSION"=>"HTTP/1.1", "rack.multithread"=>false, "HTTP_COOKIE"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "action_dispatch.request.request_parameters"=>{}, "rack.multiprocess"=>false, "REQUEST_URI"=>"http://localhost:3000/store/add_to_cart/wibble", "rack.request.query_hash"=>{}, "SERVER_PORT"=>"3000", "action_controller.instance"=>#<StoreController:0x5ede578 ...>, "rack.session.options"=>{:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}, "REQUEST_METHOD"=>"GET", "rack.request.query_string"=>"", "action_dispatch.request.content_type"=>nil, "rack.input"=>#<StringIO:0x5fced70>, "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1"}>, @_env={"action_dispatch.request.formats"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "action_dispatch.request.parameters"=>{"action"=>"add_to_cart", "id"=>"wibble", "controller"=>"store"}, "rack.session.record"=>#<ActiveRecord::SessionStore::Session id: 2, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7BiIJY2FydG86CUNhcnQGOgtAaXRlbXNbB286DUNhcnRJdGV...", created_at: "2010-02-25 15:49:06", updated_at: "2010-02-25 15:49:06">, "rack.session"=>{"cart"=>#<Cart:0x5f55450 @items=[#<CartItem:0x5f553d8 @product=#<Product id: 2, title: "Pragmatic Project Automation", description: "<p>\n <em>Pragmatic Project Automation</em> sh...", image_url: "/images/auto.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:5df6330,'0.2995E2',8(8)>>, @quantity=2>, #<CartItem:0x5f550d8 @product=#<Product id: 3, title: "Pragmatic Version Control", description: "<p>\n This book is a recipe-based approach t...", image_url: "/images/svn.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:5df5dc0,'0.285E2',8(8)>>, @quantity=1>]>}, "HTTP_HOST"=>"localhost:3000", "HTTP_ACCEPT"=>"text/html", "SERVER_NAME"=>"localhost", "rack.request.cookie_hash"=>{"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}, "REQUEST_PATH"=>"/", "rack.url_scheme"=>"http", "REMOTE_HOST"=>"rubix4", "action_dispatch.request.query_parameters"=>{}, "rack.errors"=>#<IO:0x2feda90>, "SERVER_PROTOCOL"=>"HTTP/1.1", "action_dispatch.request.accepts"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "rack.version"=>[1, 1], "rack.run_once"=>false, "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)", "REMOTE_ADDR"=>"127.0.0.1", "PATH_INFO"=>"/store/add_to_cart/wibble", "action_dispatch.request.path_parameters"=>{:controller=>"store", :action=>"add_to_cart", :id=>"wibble"}, "rack.request.cookie_string"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "SCRIPT_NAME"=>"", "action_dispatch.parameter_filter"=>[:password], "HTTP_VERSION"=>"HTTP/1.1", "rack.multithread"=>false, "HTTP_COOKIE"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "action_dispatch.request.request_parameters"=>{}, "rack.multiprocess"=>false, "REQUEST_URI"=>"http://localhost:3000/store/add_to_cart/wibble", "rack.request.query_hash"=>{}, "SERVER_PORT"=>"3000", "action_controller.instance"=>#<StoreController:0x5ede578 ...>, "rack.session.options"=>{:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}, "REQUEST_METHOD"=>"GET", "rack.request.query_string"=>"", "action_dispatch.request.content_type"=>nil, "rack.input"=>#<StringIO:0x5fced70>, "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1"}, @_headers={}, @_action_name="add_to_cart", @template=#<Class>>
action_dispatch.parameter_filter: [:password]
action_dispatch.request.accepts: [#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>]
action_dispatch.request.content_type: nil
action_dispatch.request.formats: [#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>]
action_dispatch.request.parameters: {"action"=>"add_to_cart", "id"=>"wibble", "controller"=>"store"}
action_dispatch.request.path_parameters: {:controller=>"store", :action=>"add_to_cart", :id=>"wibble"}
action_dispatch.request.query_parameters: {}
action_dispatch.request.request_parameters: {}
rack.errors: #<IO:0x2feda90>
rack.input: #<StringIO:0x5fced70>
rack.multiprocess: false
rack.multithread: false
rack.request.cookie_hash: {"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}
rack.request.cookie_string: "_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly"
rack.request.query_hash: {}
rack.request.query_string: ""
rack.run_once: false
rack.session: {"cart"=>#<Cart:0x5f55450 @items=[#<CartItem:0x5f553d8 @product=#<Product id: 2, title: "Pragmatic Project Automation", description: "<p>\n <em>Pragmatic Project Automation</em> sh...", image_url: "/images/auto.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:5df4758,'0.2995E2',8(8)>>, @quantity=2>, #<CartItem:0x5f550d8 @product=#<Product id: 3, title: "Pragmatic Version Control", description: "<p>\n This book is a recipe-based approach t...", image_url: "/images/svn.jpg", created_at: "2010-02-25 15:48:29", updated_at: "2010-02-25 15:48:29", price: #<BigDecimal:5df41e8,'0.285E2',8(8)>>, @quantity=1>]>}
rack.session.options: {:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}
rack.session.record: #<ActiveRecord::SessionStore::Session id: 2, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7BiIJY2FydG86CUNhcnQGOgtAaXRlbXNbB286DUNhcnRJdGV...", created_at: "2010-02-25 15:49:06", updated_at: "2010-02-25 15:49:06">
rack.url_scheme: "http"
rack.version: [1, 1]
Response
Headers :
None
8.4 Iteration C3: Handling Errors
edit app\controllers\store_controller.rb
def add_to_cart
product = Product.find(params[:id])
@cart = find_cart
@cart.add_product(product)
rescue ActiveRecord::RecordNotFound
logger.error("Attempt to access invalid product #{params[:id]}")
flash[:notice] = "Invalid product"
redirect_to :action => 'index'
end
get /store/add_to_cart/wibble
You are being
redirected .
get http://localhost:3000/store
Pragmatic Bookshelf
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
tail -99 log\development.log
SQL (0.0ms) PRAGMA index_info('index_sessions_on_session_id')
Started GET "/store/add_to_cart/2" for 127.0.0.1 at 2010-02-25 10:48:58
Processing by StoreController#add_to_cart as HTML
Parameters: {"id"=>"2"}
Product Load (0.0ms) SELECT "products".* FROM "products" WHERE ("products"."id" = 2) LIMIT 1
ActionView::MissingTemplate (Missing template store/add_to_cart with {:locale=>[:en], :formats=>[:html]} in view paths "C:/cygwin/home/rubys/git/awdwr/work/depot/app/views"):
Rendered C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb within C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb (0.0ms)
Started GET "/store/add_to_cart/2" for 127.0.0.1 at 2010-02-25 10:48:58
Processing by StoreController#add_to_cart as HTML
Parameters: {"id"=>"2"}
Product Load (0.0ms) SELECT "products".* FROM "products" WHERE ("products"."id" = 2) LIMIT 1
Rendered store/add_to_cart.html.erb within layouts/store.html.erb (6.0ms)
Completed 200 OK in 32ms (Views: 12.0ms | ActiveRecord: 0.0ms)
Started GET "/store/add_to_cart/3" for 127.0.0.1 at 2010-02-25 10:48:59
Processing by StoreController#add_to_cart as HTML
Parameters: {"id"=>"3"}
Product Load (0.0ms) *[1mSELECT "products".* FROM "products" WHERE ("products"."id" = 3) LIMIT 1*[0m
Rendered store/add_to_cart.html.erb within layouts/store.html.erb (6.0ms)
Completed 200 OK in 18ms (Views: 14.0ms | ActiveRecord: 0.0ms)
Started GET "/store/add_to_cart/2" for 127.0.0.1 at 2010-02-25 10:48:59
Processing by StoreController#add_to_cart as HTML
Parameters: {"id"=>"2"}
Product Load (1.0ms) SELECT "products".* FROM "products" WHERE ("products"."id" = 2) LIMIT 1
NoMethodError (undefined method `product' for #<Product:0x4ac3670>):
app/models/cart.rb:10:in `add_product'
app/models/cart.rb:10:in `each'
app/models/cart.rb:10:in `find'
app/models/cart.rb:10:in `add_product'
app/controllers/store_controller.rb:11:in `add_to_cart'
Rendered C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms)
Rendered C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (7.0ms)
Rendered C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb (35.0ms)
SQL (8.0ms) *[1mDELETE FROM sessions*[0m
Started GET "/store/add_to_cart/2" for 127.0.0.1 at 2010-02-25 10:49:06
Processing by StoreController#add_to_cart as HTML
Parameters: {"id"=>"2"}
Product Load (0.0ms) SELECT "products".* FROM "products" WHERE ("products"."id" = 2) LIMIT 1
Rendered store/add_to_cart.html.erb within layouts/store.html.erb (5.0ms)
Completed 200 OK in 39ms (Views: 13.0ms | ActiveRecord: 1.0ms)
Started GET "/store/add_to_cart/2" for 127.0.0.1 at 2010-02-25 10:49:06
Processing by StoreController#add_to_cart as HTML
Parameters: {"id"=>"2"}
Product Load (1.0ms) SELECT "products".* FROM "products" WHERE ("products"."id" = 2) LIMIT 1
Rendered store/add_to_cart.html.erb within layouts/store.html.erb (2.0ms)
Completed 200 OK in 16ms (Views: 9.0ms | ActiveRecord: 2.0ms)
Started GET "/store/add_to_cart/3" for 127.0.0.1 at 2010-02-25 10:49:06
Processing by StoreController#add_to_cart as HTML
Parameters: {"id"=>"3"}
Product Load (1.0ms) SELECT "products".* FROM "products" WHERE ("products"."id" = 3) LIMIT 1
Rendered store/add_to_cart.html.erb within layouts/store.html.erb (2.0ms)
Completed 200 OK in 16ms (Views: 9.0ms | ActiveRecord: 2.0ms)
Started GET "/store/add_to_cart/wibble" for 127.0.0.1 at 2010-02-25 10:49:07
Processing by StoreController#add_to_cart as HTML
Parameters: {"id"=>"wibble"}
Product Load (1.0ms) SELECT "products".* FROM "products" WHERE ("products"."id" = 0) LIMIT 1
ActiveRecord::RecordNotFound (Couldn't find Product with ID=wibble):
app/controllers/store_controller.rb:9:in `add_to_cart'
Rendered C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms)
Rendered C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (16.0ms)
Rendered C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb (44.0ms)
Started GET "/store/add_to_cart/wibble" for 127.0.0.1 at 2010-02-25 10:49:07
Processing by StoreController#add_to_cart as HTML
Parameters: {"id"=>"wibble"}
Product Load (1.0ms) *[1mSELECT "products".* FROM "products" WHERE ("products"."id" = 0) LIMIT 1*[0m
Attempt to access invalid product wibble
Redirected to http://localhost:3000/store
Completed 302 Found in 14ms
Started GET "/store" for 127.0.0.1 at 2010-02-25 10:49:07
Processing by StoreController#index as */*
Product Load (1.0ms) *[1mSELECT "products".* FROM "products" ORDER BY title*[0m
Rendered store/index.html.erb within layouts/store.html.erb (14.0ms)
Completed 200 OK in 33ms (Views: 30.0ms | ActiveRecord: 2.0ms)
edit app\views\layouts\store.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Pragprog Books Online Store</title>
<%= stylesheet_link_tag "depot", :media => "all" %>
</head>
<body id="store">
<div id="banner">
<%= image_tag("logo.png") %>
<%= @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 -%>
<%= yield :layout %>
</div>
</div>
</body>
</html>
edit public\stylesheets\depot.css
#notice {
border: 2px solid red;
padding: 1em;
margin-bottom: 2em;
background-color: #f0f0f0;
font: bold smaller sans-serif;
}
get /store/add_to_cart/wibble
You are being
redirected .
get http://localhost:3000/store
Pragmatic Bookshelf
Invalid product
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
8.5 Iteration C4: Finishing the Cart
edit app\views\store\add_to_cart.html.erb
<h2>Your Pragmatic Cart</h2>
<ul>
<% for item in @cart.items %>
<li><%= item.quantity %> × <%= item.title %></li>
<% end %>
</ul>
<%= button_to 'Empty cart', :action => 'empty_cart' %>
edit app\controllers\store_controller.rb
def empty_cart
session[:cart] = nil
flash[:notice] = "Your cart is currently empty"
redirect_to :action => 'index'
end
get /store/empty_cart
You are being
redirected .
get http://localhost:3000/store
Pragmatic Bookshelf
Your cart is currently empty
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
edit app\controllers\store_controller.rb
def add_to_cart
product = Product.find(params[:id])
@cart = find_cart
@cart.add_product(product)
rescue ActiveRecord::RecordNotFound
logger.error("Attempt to access invalid product #{params[:id]}")
redirect_to_index("Invalid product")
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
edit app\views\store\add_to_cart.html.erb
<div class="cart-title">Your Cart</div>
<table>
<% for item in @cart.items %>
<tr>
<td><%= item.quantity %>×</td>
<td><%=h item.title %></td>
<td class="item-price"><%= number_to_currency(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 %>
edit public\stylesheets\depot.css
/* Styles for the cart in the main page */
.cart-title {
font: 120% bold;
}
.item-price, .total-line {
text-align: right;
}
.total-line .total-cell {
font-weight: bold;
border-top: 1px solid #595;
}
edit app\models\cart.rb
class Cart
attr_reader :items # <wtf linkend="wtf.attr.accessor">attr_reader</wtf>
def initialize
@items = []
end
def add_product(product)
current_item = @items.find {|item| item.product == product}
if current_item
current_item.increment_quantity
else
@items << CartItem.new(product)
end
end
def total_price
@items.sum { |item| item.price }
end
end
get /store/add_to_cart/2
Pragmatic Bookshelf
get /store/add_to_cart/2
Pragmatic Bookshelf
get /store/add_to_cart/3
Pragmatic Bookshelf
9.1 Iteration D1: Moving the Cart
edit app\views\store\add_to_cart.html.erb
<div class="cart-title">Your Cart</div>
<table>
<%= render(:partial => "cart_item", :collection => @cart.items) %>
<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 %>
edit app\views\store\_cart_item.html.erb
<tr>
<td><%= cart_item.quantity %>×</td>
<td><%= cart_item.title %></td>
<td class="item-price"><%= number_to_currency(cart_item.price) %></td>
</tr>
cp app\views\store\add_to_cart.html.erb app\views\store\_cart.html.erb
edit app\views\store\_cart.html.erb
<div class="cart-title">Your Cart</div>
<table>
<%= render(:partial => "cart_item", :collection => cart.items) %>
<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 %>
edit app\views\layouts\store.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Pragprog Books Online Store</title>
<%= stylesheet_link_tag "depot", :media => "all" %>
</head>
<body id="store">
<div id="banner">
<%= image_tag("logo.png") %>
<%= @page_title || "Pragmatic Bookshelf" %>
</div>
<div id="columns">
<div id="side">
<div id="cart">
<%= render(:partial => "cart", :object => @cart) %>
</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 />
</div>
<div id="main">
<% if flash[:notice] -%>
<div id="notice"><%= flash[:notice] %></div>
<% end -%>
<%= yield :layout %>
</div>
</div>
</body>
</html>
edit app\controllers\store_controller.rb
def index
@products = Product.find_products_for_sale
@cart = find_cart
end
edit public\stylesheets\depot.css
/* Styles for the cart in the sidebar */
#cart, #cart table {
font-size: smaller;
color: white;
}
#cart table {
border-top: 1px dotted #595;
border-bottom: 1px dotted #595;
margin-bottom: 10px;
}
get /store
Pragmatic Bookshelf
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
edit app\controllers\store_controller.rb
def add_to_cart
product = Product.find(params[:id])
@cart = find_cart
@cart.add_product(product)
redirect_to_index
rescue ActiveRecord::RecordNotFound
logger.error("Attempt to access invalid product #{params[:id]}")
redirect_to_index("Invalid product")
end
edit app\controllers\store_controller.rb
def redirect_to_index(msg = nil)
flash[:notice] = msg if msg
redirect_to :action => 'index'
end
rm app\views\store\add_to_cart.html.erb
get /store/add_to_cart/3
You are being
redirected .
get http://localhost:3000/store
Pragmatic Bookshelf
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
9.2 Iteration D2: Creating an AJAX-Based Cart
edit app\views\store\index.html.erb
<% form_tag({:action=>'add_to_cart', :id=>product}, :remote=>true) do %>
<%= submit_tag "Add to Cart" %>
<% end %>
edit app\views\layouts\store.html.erb
<html>
<head>
<title>Pragprog Books Online Store</title>
<%= stylesheet_link_tag "depot", :media => "all" %>
<%= javascript_include_tag :defaults %>
</head>
edit app\controllers\store_controller.rb
def add_to_cart
product = Product.find(params[:id])
@cart = find_cart
@cart.add_product(product)
respond_to do |format|
format.js
end
rescue ActiveRecord::RecordNotFound
logger.error("Attempt to access invalid product #{params[:id]}")
redirect_to_index("Invalid product")
end
edit app\views\store\add_to_cart.js.rjs
page.replace_html("cart", :partial => "cart", :object => @cart)
9.3 Iteration D3: Highlighting Changes
edit app\models\cart.rb
class Cart
attr_reader :items # <wtf linkend="wtf.attr.accessor">attr_reader</wtf>
def initialize
@items = []
end
def add_product(product)
current_item = @items.find {|item| item.product == product}
if current_item
current_item.increment_quantity
else
current_item = CartItem.new(product)
@items << current_item
end
current_item
end
def total_price
@items.sum { |item| item.price }
end
end
edit app\controllers\store_controller.rb
def add_to_cart
product = Product.find(params[:id])
@cart = find_cart
@current_item = @cart.add_product(product)
respond_to do |format|
format.js
end
rescue ActiveRecord::RecordNotFound
logger.error("Attempt to access invalid product #{params[:id]}")
redirect_to_index("Invalid product")
end
edit app\views\store\_cart_item.html.erb
<% if cart_item == @current_item %>
<tr id="current_item">
<% else %>
<tr>
<% end %>
<td><%= cart_item.quantity %>×</td>
<td><%= cart_item.title %></td>
<td class="item-price"><%= number_to_currency(cart_item.price) %></td>
</tr>
edit app\views\store\add_to_cart.js.rjs
page.replace_html("cart", :partial => "cart", :object => @cart)
page[:current_item].visual_effect :highlight,
:startcolor => "#88ff88",
:endcolor => "#114411"
9.4 Iteration D4: Hide an Empty Cart
edit app\views\store\add_to_cart.js.rjs
page.replace_html("cart", :partial => "cart", :object => @cart)
page[:cart].visual_effect :blind_down if @cart.total_items == 1
page[:current_item].visual_effect :highlight,
:startcolor => "#88ff88",
:endcolor => "#114411"
edit app\models\cart.rb
class Cart
attr_reader :items # <wtf linkend="wtf.attr.accessor">attr_reader</wtf>
def initialize
@items = []
end
def add_product(product)
current_item = @items.find {|item| item.product == product}
if current_item
current_item.increment_quantity
else
current_item = CartItem.new(product)
@items << current_item
end
current_item
end
def total_price
@items.sum { |item| item.price }
end
def total_items
@items.sum { |item| item.quantity }
end
end
dir/w app
Volume in drive C is ACER
Volume Serial Number is 0412-C06E
Directory of C:\cygwin\home\rubys\git\awdwr\work\depot\app
[.] [..] [controllers] [helpers] [models]
[views]
0 File(s) 0 bytes
6 Dir(s) 99,148,402,688 bytes free
dir/w app\helpers
Volume in drive C is ACER
Volume Serial Number is 0412-C06E
Directory of C:\cygwin\home\rubys\git\awdwr\work\depot\app\helpers
[.] [..] application_helper.rb
products_helper.rb store_helper.rb
3 File(s) 78 bytes
2 Dir(s) 99,148,402,688 bytes free
edit app\views\layouts\store.html.erb
<% hidden_div_if(@cart.items.empty?, :id => "cart") do %>
<%= render(:partial => "cart", :object => @cart) %>
<% end %>
edit app\helpers\store_helper.rb
module StoreHelper
def hidden_div_if(condition, attributes = {}, &block)
if condition
attributes["style"] = "display: none"
end
content_tag("div", attributes, &block)
end
end
edit app\controllers\store_controller.rb
def empty_cart
session[:cart] = nil
redirect_to_index
end
9.5 Iteration D5: Degrading If Javascript Is Disabled
edit app\controllers\store_controller.rb
def add_to_cart
product = Product.find(params[:id])
@cart = find_cart
@current_item = @cart.add_product(product)
respond_to do |format|
format.js if request.xhr?
format.html {redirect_to_index}
end
rescue ActiveRecord::RecordNotFound
logger.error("Attempt to access invalid product #{params[:id]}")
redirect_to_index("Invalid product")
end
get /store/empty_cart
You are being
redirected .
get http://localhost:3000/store
Pragmatic Bookshelf
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
get /store/add_to_cart/3
You are being
redirected .
get http://localhost:3000/store
Pragmatic Bookshelf
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
10.1 Iteration E1: Capturing an Order
ruby script\rails generate scaffold order name:string address:text email:string pay_type:string
invoke active_record
create db/migrate/20100225154924_create_orders.rb
create app/models/order.rb
invoke test_unit
create test/unit/order_test.rb
create test/fixtures/orders.yml
route resources :orders
invoke scaffold_controller
create app/controllers/orders_controller.rb
invoke erb
create app/views/orders
create app/views/orders/index.html.erb
create app/views/orders/edit.html.erb
create app/views/orders/show.html.erb
create app/views/orders/new.html.erb
create app/views/orders/_form.html.erb
create app/views/layouts/orders.html.erb
invoke test_unit
create test/functional/orders_controller_test.rb
invoke helper
create app/helpers/orders_helper.rb
invoke test_unit
create test/unit/helpers/orders_helper_test.rb
invoke stylesheets
identical public/stylesheets/scaffold.css
ruby script\rails generate scaffold line_item product_id:integer order_id:integer quantity:integer total_price:decimal
invoke active_record
create db/migrate/20100225154930_create_line_items.rb
create app/models/line_item.rb
invoke test_unit
create test/unit/line_item_test.rb
create test/fixtures/line_items.yml
route resources :line_items
invoke scaffold_controller
create app/controllers/line_items_controller.rb
invoke erb
create app/views/line_items
create app/views/line_items/index.html.erb
create app/views/line_items/edit.html.erb
create app/views/line_items/show.html.erb
create app/views/line_items/new.html.erb
create app/views/line_items/_form.html.erb
create app/views/layouts/line_items.html.erb
invoke test_unit
create test/functional/line_items_controller_test.rb
invoke helper
create app/helpers/line_items_helper.rb
invoke test_unit
create test/unit/helpers/line_items_helper_test.rb
invoke stylesheets
identical public/stylesheets/scaffold.css
edit db\migrate\20100225154924_create_orders.rb
def self.up
create_table :orders do |t|
t.string :name
t.text :address
t.string :email
t.string :pay_type, :limit => 10
t.timestamps
end
end
edit db\migrate\20100225154930_create_line_items.rb
class CreateLineItems < ActiveRecord::Migration
def self.up
create_table :line_items do |t|
t.integer :product_id, :null => false, :options =>
"CONSTRAINT fk_line_item_products REFERENCES products(id)"
t.integer :order_id, :null => false, :options =>
"CONSTRAINT fk_line_item_orders REFERENCES orders(id)"
t.integer :quantity, :null => false
t.decimal :total_price, :null => false, :precision => 8, :scale => 2
t.timestamps
end
end
def self.down
drop_table :line_items
end
end
rake db:migrate
mv 20100225154924_create_orders.rb 20100301000005_create_orders.rb
mv 20100225154930_create_line_items.rb 20100301000006_create_line_items.rb
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
== CreateOrders: migrating ===================================================
-- create_table(:orders)
-> 0.0020s
== CreateOrders: migrated (0.0020s) ==========================================
== CreateLineItems: migrating ================================================
-- create_table(:line_items)
-> 0.0030s
== CreateLineItems: migrated (0.0030s) =======================================
sqlite3 db\development.sqlite3 .schema
CREATE TABLE "line_items" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "product_id" integer NOT NULL, "order_id" integer NOT NULL, "quantity" integer NOT NULL, "total_price" decimal(8,2) NOT NULL, "created_at" datetime, "updated_at" datetime);
CREATE TABLE "orders" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255), "address" text, "email" varchar(255), "pay_type" varchar(10), "created_at" datetime, "updated_at" datetime);
CREATE TABLE "products" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(255), "description" text, "image_url" varchar(255), "created_at" datetime, "updated_at" datetime, "price" decimal(8,2) DEFAULT 0);
CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL);
CREATE TABLE "sessions" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "session_id" varchar(255) NOT NULL, "data" text, "created_at" datetime, "updated_at" datetime);
CREATE INDEX "index_sessions_on_session_id" ON "sessions" ("session_id");
CREATE INDEX "index_sessions_on_updated_at" ON "sessions" ("updated_at");
CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version");
edit app\models\order.rb
class Order < ActiveRecord::Base
has_many :line_items
end
edit app\models\product.rb
class Product < ActiveRecord::Base
has_many :line_items
# ...
edit app\models\line_item.rb
class LineItem < ActiveRecord::Base
belongs_to :order
belongs_to :product
end
edit app\views\store\_cart.html.erb
<div class="cart-title">Your Cart</div>
<table>
<%= render(:partial => "cart_item", :collection => cart.items) %>
<tr class="total-line">
<td colspan="2">Total</td>
<td class="total-cell"><%= number_to_currency(cart.total_price) %></td>
</tr>
</table>
<%= button_to "Checkout", :action => 'checkout' %>
<%= button_to "Empty cart", :action => :empty_cart %>
edit app\controllers\store_controller.rb
def checkout
@cart = find_cart
if @cart.items.empty?
redirect_to_index("Your cart is empty")
else
@order = Order.new
end
end
edit app\views\store\checkout.html.erb
<div class="depot-form">
<%= error_messages_for 'order' %>
<% form_for :order, :url => { :action => :save_order } do |form| %>
<fieldset>
<legend>Please Enter Your Details</legend>
<div>
<%= form.label :name, "Name:" %>
<%= form.text_field :name, :size => 40 %>
</div>
<div>
<%= form.label :address, "Address:" %>
<%= form.text_area :address, :rows => 3, :cols => 40 %>
</div>
<div>
<%= form.label :email, "E-Mail:" %>
<%= form.text_field :email, :size => 40 %>
</div>
<div>
<%= form.label :pay_type, "Pay with:" %>
<%=
form.select :pay_type,
Order::PAYMENT_TYPES,
:prompt => "Select a payment method"
%>
</div>
<%= submit_tag "Place Order", :class => "submit" %>
</fieldset>
<% end %>
</div>
edit app\models\order.rb
class Order < ActiveRecord::Base
PAYMENT_TYPES = [
# Displayed stored in db
[ "Check", "check" ],
[ "Credit card", "cc" ],
[ "Purchase order", "po" ]
]
# ...
edit public\stylesheets\depot.css
/* Styles for order form */
.depot-form fieldset {
background: #efe;
}
.depot-form legend {
color: #dfd;
background: #141;
font-family: sans-serif;
padding: 0.2em 1em;
}
.depot-form label {
width: 5em;
float: left;
text-align: right;
padding-top: 0.2em;
margin-right: 0.1em;
display: block;
}
.depot-form select, .depot-form textarea, .depot-form input {
margin-left: 0.5em;
}
.depot-form .submit {
margin-left: 4em;
}
.depot-form div {
margin: 0.5em 0;
}
get /store/checkout
Pragmatic Bookshelf
get /store/save_order
Unknown action
The action 'save_order' could not be found
edit app\models\order.rb
class Order < ActiveRecord::Base
PAYMENT_TYPES = [
# Displayed stored in db
[ "Check", "check" ],
[ "Credit card", "cc" ],
[ "Purchase order", "po" ]
]
validates_presence_of :name, :address, :email, :pay_type
validates_inclusion_of :pay_type, :in =>
PAYMENT_TYPES.map {|disp, value| value}
# ...
edit app\controllers\store_controller.rb
def save_order
@cart = find_cart
@order = Order.new(params[:order]) # <label id="code.p.new.order"/>
@order.add_line_items_from_cart(@cart) # <label id="code.p.append.li"/>
if @order.save # <label id="code.p.save"/>
session[:cart] = nil
redirect_to_index("Thank you for your order")
else
render :action => 'checkout'
end
end
edit app\models\order.rb
class Order < ActiveRecord::Base
PAYMENT_TYPES = [
# Displayed stored in db
[ "Check", "check" ],
[ "Credit card", "cc" ],
[ "Purchase order", "po" ]
]
# ...
validates_presence_of :name, :address, :email, :pay_type
validates_inclusion_of :pay_type, :in =>
PAYMENT_TYPES.map {|disp, value| value}
# ...
has_many :line_items
def add_line_items_from_cart(cart)
cart.items.each do |item|
li = LineItem.from_cart_item(item)
line_items << li
end
end
end
edit app\models\line_item.rb
class LineItem < ActiveRecord::Base
belongs_to :order
belongs_to :product
def self.from_cart_item(cart_item)
li = self.new
li.product = cart_item.product
li.quantity = cart_item.quantity
li.total_price = cart_item.price
li
end
end
sqlite3> select * from orders
sqlite3> select * from line_items
get /store/save_order
Pragmatic Bookshelf
get /store/checkout
Pragmatic Bookshelf
post /store/save_order
order[pay_type] => check
order[address] => 123 Main St
order[email] => customer@example.com
order[name] => Dave Thomas
You are being
redirected .
get http://localhost:3000/store
Pragmatic Bookshelf
Thank you for your order
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
sqlite3> select * from orders
id = 1
name = Dave Thomas
address = 123 Main St
email = customer@example.com
pay_type = check
created_at = 2010-02-25 15:49:41.929500
updated_at = 2010-02-25 15:49:41.929500
sqlite3> select * from line_items
id = 1
product_id = 3
order_id = 1
quantity = 1
total_price = 28.5
created_at = 2010-02-25 15:49:41.933500
updated_at = 2010-02-25 15:49:41.933500
edit app\views\store\add_to_cart.js.rjs
page.select("div#notice").each { |div| div.hide }
page.replace_html("cart", :partial => "cart", :object => @cart)
page[:cart].visual_effect :blind_down if @cart.total_items == 1
page[:current_item].visual_effect :highlight,
:startcolor => "#88ff88",
:endcolor => "#114411"
11.1 Iteration F1: Adding Users
ruby script\rails generate scaffold user name:string hashed_password:string salt:string
invoke active_record
create db/migrate/20100225154948_create_users.rb
create app/models/user.rb
invoke test_unit
create test/unit/user_test.rb
create test/fixtures/users.yml
route resources :users
invoke scaffold_controller
create app/controllers/users_controller.rb
invoke erb
create app/views/users
create app/views/users/index.html.erb
create app/views/users/edit.html.erb
create app/views/users/show.html.erb
create app/views/users/new.html.erb
create app/views/users/_form.html.erb
create app/views/layouts/users.html.erb
invoke test_unit
create test/functional/users_controller_test.rb
invoke helper
create app/helpers/users_helper.rb
invoke test_unit
create test/unit/helpers/users_helper_test.rb
invoke stylesheets
identical public/stylesheets/scaffold.css
type db\migrate\20100225154948_create_users.rb
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :name
t.string :hashed_password
t.string :salt
t.timestamps
end
end
def self.down
drop_table :users
end
end
rake db:migrate
mv 20100225154948_create_users.rb 20100301000007_create_users.rb
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
== CreateUsers: migrating ====================================================
-- create_table(:users)
-> 0.0030s
== CreateUsers: migrated (0.0030s) ===========================================
edit app\models\user.rb
require 'digest/sha1'
class User < ActiveRecord::Base
validates_presence_of :name
validates_uniqueness_of :name
attr_accessor :password_confirmation
validates_confirmation_of :password
validate :password_non_blank
def self.authenticate(name, password)
user = self.find_by_name(name)
if user
expected_password = encrypted_password(password, user.salt)
if user.hashed_password != expected_password
user = nil
end
end
user
end
# 'password' is a virtual attribute
def password
@password
end
def password=(pwd)
@password = pwd
return if pwd.blank?
create_new_salt
self.hashed_password = User.encrypted_password(self.password, self.salt)
end
private
def password_non_blank
errors.add(:password, "Missing password") if hashed_password.blank?
end
def create_new_salt
self.salt = self.object_id.to_s + rand.to_s
end
def self.encrypted_password(password, salt)
string_to_hash = password + "wibble" + salt
Digest::SHA1.hexdigest(string_to_hash)
end
end
edit app\controllers\users_controller.rb
class UsersController < ApplicationController
# GET /users
# GET /users.xml
def index
@users = User.all(:order => :name)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @users }
end
end
# GET /users/1
# GET /users/1.xml
def show
@user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @user }
end
end
# GET /users/new
# GET /users/new.xml
def new
@user = User.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @user }
end
end
# GET /users/1/edit
def edit
@user = User.find(params[:id])
end
# POST /users
# POST /users.xml
def create
@user = User.new(params[:user])
respond_to do |format|
if @user.save
format.html { redirect_to(users_url,
:notice => "User #{@user.name} was successfully created.") }
format.xml { render :xml => @user, :status => :created,
:location => @user }
else
format.html { render :action => "new" }
format.xml { render :xml => @user.errors,
:status => :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.xml
def update
@user = User.find(params[:id])
respond_to do |format|
if @user.update_attributes(params[:user])
format.html { redirect_to(users_url,
:notice => "User #{@user.name} was successfully updated.") }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @user.errors,
:status => :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.xml
def destroy
@user = User.find(params[:id])
@user.destroy
respond_to do |format|
format.html { redirect_to(users_url) }
format.xml { head :ok }
end
end
end
edit app\views\users\index.html.erb
<h1>Listing users</h1>
<table>
<tr>
<th>Name</th>
<th></th>
<th></th>
<th></th>
</tr>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= link_to 'Show', user %></td>
<td><%= link_to 'Edit', edit_user_path(user) %></td>
<td><%= link_to 'Destroy', user, :confirm => 'Are you sure?',
:method => :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New user', new_user_path %>
edit app\views\users\new.html.erb
<div class="depot-form">
<% form_for(@user) do |f| %>
<%= f.error_messages %>
<fieldset>
<legend>Enter User Details</legend>
<div>
<%= f.label :name %>:
<%= f.text_field :name, :size => 40 %>
</div>
<div>
<%= f.label :password, 'Password' %>:
<%= f.password_field :password, :size => 40 %>
</div>
<div>
<%= f.label :password_confirmation, 'Confirm' %>:
<%= f.password_field :password_confirmation, :size => 40 %>
</div>
<div>
<%= f.submit "Add User", :class => "submit" %>
</div>
</fieldset>
<% end %>
</div>
edit app\views\layouts\users.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Users: <%= controller.action_name %></title>
<%= stylesheet_link_tag 'scaffold', 'depot' %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
</head>
get /users
get /users/new
post /users
user[password_confirmation] => secret
user[name] => dave
user[password] => secret
You are being
redirected .
get http://localhost:3000/users
User dave was successfully created.
Listing users
New user
sqlite3> select * from users
id = 1
name = dave
hashed_password = 9ce99a3104e1a8cea9c26429eaa8b7690a39bee9
salt = 493303080.417682255535711
created_at = 2010-02-25 15:49:56.558500
updated_at = 2010-02-25 15:49:56.558500
11.2 Iteration F2: Logging in
ruby script\rails generate controller admin login logout index
create app/controllers/admin_controller.rb
invoke erb
create app/views/admin
create app/views/admin/login.html.erb
create app/views/admin/logout.html.erb
create app/views/admin/index.html.erb
invoke test_unit
create test/functional/admin_controller_test.rb
invoke helper
create app/helpers/admin_helper.rb
invoke test_unit
create test/unit/helpers/admin_helper_test.rb
edit app\controllers\admin_controller.rb
class AdminController < ApplicationController
# just display the form and wait for user to
# enter a name and password
def login
if request.post?
user = User.authenticate(params[:name], params[:password])
if user
session[:user_id] = user.id
redirect_to(:action => "index")
else
flash.now[:notice] = "Invalid user/password combination"
end
end
end
def logout
session[:user_id] = nil
flash[:notice] = "Logged out"
redirect_to(:action => "login")
end
def index
@total_orders = Order.count
end
end
edit app\views\admin\login.html.erb
<div class="depot-form">
<% form_tag do %>
<fieldset>
<legend>Please Log In</legend>
<div>
<label for="name">Name:</label>
<%= text_field_tag :name, params[:name] %>
</div>
<div>
<label for="password">Password:</label>
<%= password_field_tag :password, params[:password] %>
</div>
<div>
<%= submit_tag "Login" %>
</div>
</fieldset>
<% end %>
</div>
edit app\views\admin\index.html.erb
<h1>Welcome</h1>
It's <%= Time.now %>
We have <%= pluralize(@total_orders, "order") %>.
get /admin/login
post /admin/login
name => dave
password => secret
You are being
redirected .
get http://localhost:3000/admin
Welcome
It's Thu Feb 25 10:50:03 -0500 2010
We have 1 order.
11.3 Iteration F3: Limiting Access
edit app\controllers\application_controller.rb
class ApplicationController < ActionController::Base
before_filter :authorize, :except => :login
protect_from_forgery
protected
def authorize
unless User.find_by_id(session[:user_id])
flash[:notice] = "Please log in"
redirect_to :controller => 'admin', :action => 'login'
end
end
end
edit app\controllers\store_controller.rb
class StoreController < ApplicationController
def index
@products = Product.find_products_for_sale
@cart = find_cart
end
def add_to_cart
product = Product.find(params[:id])
@cart = find_cart
@current_item = @cart.add_product(product)
respond_to do |format|
format.js if request.xhr?
format.html {redirect_to_index}
end
rescue ActiveRecord::RecordNotFound
logger.error("Attempt to access invalid product #{params[:id]}")
redirect_to_index("Invalid product")
end
def checkout
@cart = find_cart
if @cart.items.empty?
redirect_to_index("Your cart is empty")
else
@order = Order.new
end
end
def save_order
@cart = find_cart
@order = Order.new(params[:order])
@order.add_line_items_from_cart(@cart)
if @order.save
session[:cart] = nil
redirect_to_index("Thank you for your order")
else
render :action => 'checkout'
end
end
def empty_cart
session[:cart] = nil
redirect_to_index
end
private
def redirect_to_index(msg = nil)
flash[:notice] = msg if msg
redirect_to :action => 'index'
end
def find_cart
session[:cart] ||= Cart.new
end
end
edit app\controllers\store_controller.rb
class StoreController < ApplicationController
#...
protected
def authorize
end
end
rake db:sessions:clear
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
get /admin/logout
You are being
redirected .
get http://localhost:3000/admin/login
get /store
Pragmatic Bookshelf
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
get /products
You are being
redirected .
get http://localhost:3000/admin/login
get /admin/login
post /admin/login
name => dave
password => secret
You are being
redirected .
get http://localhost:3000/admin
Welcome
It's Thu Feb 25 10:50:12 -0500 2010
We have 1 order.
get /products
11.4 Iteration F4: Adding a Sidebar, More Administration
</=> #<Product id: nil/> expected but was
<"class ApplicationController < ActionController::Base">.
Traceback:
C:/cygwin/home/rubys/git/awdwr/work/vendor/rails/actionpack/lib/action_dispatch/testing/assertions/selector.rb:303:in `assert_select'
C:/cygwin/home/rubys/git/awdwr/checkdepot.rb:164
c:\cygwin\home\rubys\git\gorp\lib/gorp/test.rb:53:in `instance_eval'
c:\cygwin\home\rubys\git\gorp\lib/gorp/test.rb:53:in `section'
c:\cygwin\home\rubys\git\gorp\lib/gorp/test.rb:39:in `instance_eval'
c:\cygwin\home\rubys\git\gorp\lib/gorp/test.rb:39:in `test_11.4_Iteration_F4:_A_Sidebar,_More_Administration'
edit app\controllers\application_controller.rb
class ApplicationController < ActionController::Base
layout "store"
#...
get /admin
NoMethodError in
Admin#index
Showing C:/cygwin/home/rubys/git/awdwr/work/depot/app/views/layouts/store.html.erb where line #24 raised:
undefined method `items' for nil:NilClass
Extracted source (around line #24 ):
21: <div id="side">
22: <!-- START_HIGHLIGHT -->
23: <!-- START:hidden_div -->
24: <% hidden_div_if(@cart.items.empty?, :id => "cart") do %>
25: <%= render(:partial => "cart", :object => @cart) %>
26: <% end %>
27: <!-- END:hidden_div -->
Rails.root: C:/cygwin/home/rubys/git/awdwr/work/depot
Application Trace |
Framework Trace |
Full Trace
On line #24 of c:/cygwin/home/rubys/git/awdwr/work/depot/app/views/layouts/store.html.erb
21: <div id="side">
22: <!-- START_HIGHLIGHT -->
23: <!-- START:hidden_div -->
24: <% hidden_div_if(@cart.items.empty?, :id => "cart") do %>
25: <%= render(:partial => "cart", :object => @cart) %>
26: <% end %>
27: <!-- END:hidden_div -->
app/views/layouts/store.html.erb:24:in `_render_template__975835594_68124156_0'
On line #24 of c:/cygwin/home/rubys/git/awdwr/work/depot/app/views/layouts/store.html.erb
21: <div id="side">
22: <!-- START_HIGHLIGHT -->
23: <!-- START:hidden_div -->
24: <% hidden_div_if(@cart.items.empty?, :id => "cart") do %>
25: <%= render(:partial => "cart", :object => @cart) %>
26: <% end %>
27: <!-- END:hidden_div -->
app/views/layouts/store.html.erb:24:in `_render_template__975835594_68124156_0'
Request
Parameters :
None
Show session dump
_csrf_token: "pL301iwHD7qjCt6YNAE79PYUO3bYUuchfmfL1SEmtws="
cart: #<Cart:0x5cc41e0 @items=[]>
user_id: 1
Show env dump
GATEWAY_INTERFACE: "CGI/1.1"
HTTP_ACCEPT: "text/html"
HTTP_COOKIE: "_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly"
HTTP_HOST: "localhost:3000"
HTTP_VERSION: "HTTP/1.1"
PATH_INFO: "/admin"
QUERY_STRING: ""
REMOTE_ADDR: "127.0.0.1"
REMOTE_HOST: "rubix4"
REQUEST_METHOD: "GET"
REQUEST_PATH: "/"
REQUEST_URI: "http://localhost:3000/admin"
SCRIPT_NAME: ""
SERVER_NAME: "localhost"
SERVER_PORT: "3000"
SERVER_PROTOCOL: "HTTP/1.1"
SERVER_SOFTWARE: "WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)"
action_controller.instance: #<AdminController:0x3c1af88 @_formats=[:html], @total_orders=1, @_response_body=nil, @_response=#<ActionDispatch::Response:0x3c160c8 @etag=nil, @sending_file=false, @length=0, @cache_control={}, @cookie=[], @body=[], @header={}, @block=nil, @writer=#<Proc:0x05e42698@C:/cygwin/home/rubys/git/rails/actionpack/lib/action_dispatch/http/response.rb:42>, @status=200, @request=#<ActionDispatch::Request:0x3c19c20 @filtered_parameters={"action"=>"index", "controller"=>"admin"}, @env={"action_dispatch.request.formats"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "action_dispatch.request.parameters"=>{"action"=>"index", "controller"=>"admin"}, "rack.session.record"=>#<ActiveRecord::SessionStore::Session id: 3, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7CCIQX2NzcmZfdG9rZW4iMXBMMzAxaXdIRDdxakN0NllOQUU...", created_at: "2010-02-25 15:50:10", updated_at: "2010-02-25 15:50:12">, "rack.session"=>{"_csrf_token"=>"pL301iwHD7qjCt6YNAE79PYUO3bYUuchfmfL1SEmtws=", "cart"=>#<Cart:0x5cc41e0 @items=[]>, "user_id"=>1}, "HTTP_HOST"=>"localhost:3000", "HTTP_ACCEPT"=>"text/html", "SERVER_NAME"=>"localhost", "rack.request.cookie_hash"=>{"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}, "REQUEST_PATH"=>"/", "rack.url_scheme"=>"http", "REMOTE_HOST"=>"rubix4", "action_dispatch.request.query_parameters"=>{}, "rack.errors"=>#<IO:0x2feda90>, "SERVER_PROTOCOL"=>"HTTP/1.1", "action_dispatch.request.accepts"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "rack.version"=>[1, 1], "rack.run_once"=>false, "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)", "REMOTE_ADDR"=>"127.0.0.1", "PATH_INFO"=>"/admin", "action_dispatch.request.path_parameters"=>{:controller=>"admin", :action=>"index"}, "rack.request.cookie_string"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "SCRIPT_NAME"=>"", "action_dispatch.parameter_filter"=>[:password], "HTTP_VERSION"=>"HTTP/1.1", "rack.multithread"=>false, "HTTP_COOKIE"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "action_dispatch.request.request_parameters"=>{}, "rack.multiprocess"=>false, "REQUEST_URI"=>"http://localhost:3000/admin", "rack.request.query_hash"=>{}, "SERVER_PORT"=>"3000", "action_controller.instance"=>#<AdminController:0x3c1af88 ...>, "rack.session.options"=>{:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}, "REQUEST_METHOD"=>"GET", "rack.request.query_string"=>"", "action_dispatch.request.content_type"=>nil, "rack.input"=>#<StringIO:0x5d2de58>, "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1"}>, @blank=false>, @_view_context=#<Class>, @_request=#<ActionDispatch::Request:0x3c19c20 @filtered_parameters={"action"=>"index", "controller"=>"admin"}, @env={"action_dispatch.request.formats"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "action_dispatch.request.parameters"=>{"action"=>"index", "controller"=>"admin"}, "rack.session.record"=>#<ActiveRecord::SessionStore::Session id: 3, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7CCIQX2NzcmZfdG9rZW4iMXBMMzAxaXdIRDdxakN0NllOQUU...", created_at: "2010-02-25 15:50:10", updated_at: "2010-02-25 15:50:12">, "rack.session"=>{"_csrf_token"=>"pL301iwHD7qjCt6YNAE79PYUO3bYUuchfmfL1SEmtws=", "cart"=>#<Cart:0x5cc41e0 @items=[]>, "user_id"=>1}, "HTTP_HOST"=>"localhost:3000", "HTTP_ACCEPT"=>"text/html", "SERVER_NAME"=>"localhost", "rack.request.cookie_hash"=>{"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}, "REQUEST_PATH"=>"/", "rack.url_scheme"=>"http", "REMOTE_HOST"=>"rubix4", "action_dispatch.request.query_parameters"=>{}, "rack.errors"=>#<IO:0x2feda90>, "SERVER_PROTOCOL"=>"HTTP/1.1", "action_dispatch.request.accepts"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "rack.version"=>[1, 1], "rack.run_once"=>false, "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)", "REMOTE_ADDR"=>"127.0.0.1", "PATH_INFO"=>"/admin", "action_dispatch.request.path_parameters"=>{:controller=>"admin", :action=>"index"}, "rack.request.cookie_string"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "SCRIPT_NAME"=>"", "action_dispatch.parameter_filter"=>[:password], "HTTP_VERSION"=>"HTTP/1.1", "rack.multithread"=>false, "HTTP_COOKIE"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "action_dispatch.request.request_parameters"=>{}, "rack.multiprocess"=>false, "REQUEST_URI"=>"http://localhost:3000/admin", "rack.request.query_hash"=>{}, "SERVER_PORT"=>"3000", "action_controller.instance"=>#<AdminController:0x3c1af88 ...>, "rack.session.options"=>{:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}, "REQUEST_METHOD"=>"GET", "rack.request.query_string"=>"", "action_dispatch.request.content_type"=>nil, "rack.input"=>#<StringIO:0x5d2de58>, "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1"}>, @_env={"action_dispatch.request.formats"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "action_dispatch.request.parameters"=>{"action"=>"index", "controller"=>"admin"}, "rack.session.record"=>#<ActiveRecord::SessionStore::Session id: 3, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7CCIQX2NzcmZfdG9rZW4iMXBMMzAxaXdIRDdxakN0NllOQUU...", created_at: "2010-02-25 15:50:10", updated_at: "2010-02-25 15:50:12">, "rack.session"=>{"_csrf_token"=>"pL301iwHD7qjCt6YNAE79PYUO3bYUuchfmfL1SEmtws=", "cart"=>#<Cart:0x5cc41e0 @items=[]>, "user_id"=>1}, "HTTP_HOST"=>"localhost:3000", "HTTP_ACCEPT"=>"text/html", "SERVER_NAME"=>"localhost", "rack.request.cookie_hash"=>{"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}, "REQUEST_PATH"=>"/", "rack.url_scheme"=>"http", "REMOTE_HOST"=>"rubix4", "action_dispatch.request.query_parameters"=>{}, "rack.errors"=>#<IO:0x2feda90>, "SERVER_PROTOCOL"=>"HTTP/1.1", "action_dispatch.request.accepts"=>[#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>], "rack.version"=>[1, 1], "rack.run_once"=>false, "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.7/2010-01-10)", "REMOTE_ADDR"=>"127.0.0.1", "PATH_INFO"=>"/admin", "action_dispatch.request.path_parameters"=>{:controller=>"admin", :action=>"index"}, "rack.request.cookie_string"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "SCRIPT_NAME"=>"", "action_dispatch.parameter_filter"=>[:password], "HTTP_VERSION"=>"HTTP/1.1", "rack.multithread"=>false, "HTTP_COOKIE"=>"_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly", "action_dispatch.request.request_parameters"=>{}, "rack.multiprocess"=>false, "REQUEST_URI"=>"http://localhost:3000/admin", "rack.request.query_hash"=>{}, "SERVER_PORT"=>"3000", "action_controller.instance"=>#<AdminController:0x3c1af88 ...>, "rack.session.options"=>{:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}, "REQUEST_METHOD"=>"GET", "rack.request.query_string"=>"", "action_dispatch.request.content_type"=>nil, "rack.input"=>#<StringIO:0x5d2de58>, "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1"}, @_headers={}, @_action_name="index", @template=#<Class>>
action_dispatch.parameter_filter: [:password]
action_dispatch.request.accepts: [#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>]
action_dispatch.request.content_type: nil
action_dispatch.request.formats: [#<Mime::Type:0x61882b0 @symbol=:html, @string="text/html", @synonyms=["application/xhtml+xml"]>]
action_dispatch.request.parameters: {"action"=>"index", "controller"=>"admin"}
action_dispatch.request.path_parameters: {:controller=>"admin", :action=>"index"}
action_dispatch.request.query_parameters: {}
action_dispatch.request.request_parameters: {}
rack.errors: #<IO:0x2feda90>
rack.input: #<StringIO:0x5d2de58>
rack.multiprocess: false
rack.multithread: false
rack.request.cookie_hash: {"HttpOnly"=>nil, "_depot_session"=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", "path"=>"/"}
rack.request.cookie_string: "_depot_session=BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA%3D%3D--8451b08068cbb9008df71bed18e01d68ed91d917; path=/; HttpOnly"
rack.request.query_hash: {}
rack.request.query_string: ""
rack.run_once: false
rack.session: {"_csrf_token"=>"pL301iwHD7qjCt6YNAE79PYUO3bYUuchfmfL1SEmtws=", "cart"=>#<Cart:0x5cc41e0 @items=[]>, "user_id"=>1}
rack.session.options: {:key=>"_depot_session", :secret=>"44b4ce6ae39297c5f9755112a48d6832f6637668837a6a783f0f6c4c8d1e97b307058f4d42aa79ee81712047dee2d371fd93c8dc761ded1b0e5526855dd578ac", :httponly=>true, :secure=>false, :cookie_only=>true, :domain=>nil, :id=>"BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGNHMFMyd0NhZ3JZcUo1TWtGRjk5UVF5LzA9Ig9zZXNzaW9uX2lkIiU4OGQxZTgzZThkZWU1Yjc0YWExOWM3YTc0NzA0M2Y3ZA==--8451b08068cbb9008df71bed18e01d68ed91d917", :expire_after=>nil, :path=>"/"}
rack.session.record: #<ActiveRecord::SessionStore::Session id: 3, session_id: "BAh7ByIQX2NzcmZfdG9rZW4iMTZvMENpSTEwcWdReFpTSlJ1ZGN...", data: "BAh7CCIQX2NzcmZfdG9rZW4iMXBMMzAxaXdIRDdxakN0NllOQUU...", created_at: "2010-02-25 15:50:10", updated_at: "2010-02-25 15:50:12">
rack.url_scheme: "http"
rack.version: [1, 1]
Response
Headers :
None
get /users
edit app\views\layouts\store.html.erb
<% if @cart %>
<% hidden_div_if(@cart.items.empty?, :id => "cart") do %>
<%= render(:partial => "cart", :object => @cart) %>
<% end %>
<% end %>
get /admin
Pragmatic Bookshelf
Welcome
It's Thu Feb 25 10:50:14 -0500 2010
We have 1 order.
get /users
rm app\views\layouts\products.html.erb
rm app\views\layouts\users.html.erb
rm app\views\layouts\orders.html.erb
get /users
Pragmatic Bookshelf
edit app\models\user.rb
require 'digest/sha1'
class User < ActiveRecord::Base
validates_presence_of :name
validates_uniqueness_of :name
attr_accessor :password_confirmation
validates_confirmation_of :password
validate :password_non_blank
def self.authenticate(name, password)
user = self.find_by_name(name)
if user
expected_password = encrypted_password(password, user.salt)
if user.hashed_password != expected_password
user = nil
end
end
user
end
# 'password' is a virtual attribute
def password
@password
end
def password=(pwd)
@password = pwd
return if pwd.blank?
create_new_salt
self.hashed_password = User.encrypted_password(self.password, self.salt)
end
after_destroy :ensure_an_admin_remains
def ensure_an_admin_remains
if User.count.zero?
raise "Can't delete last user"
end
end
private
def password_non_blank
errors.add(:password, "Missing password") if hashed_password.blank?
end
def create_new_salt
self.salt = self.object_id.to_s + rand.to_s
end
def self.encrypted_password(password, salt)
string_to_hash = password + "wibble" + salt
Digest::SHA1.hexdigest(string_to_hash)
end
end
edit app\controllers\users_controller.rb
class UsersController < ApplicationController
# GET /users
# GET /users.xml
def index
@users = User.all(:order => :name)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @users }
end
end
# GET /users/1
# GET /users/1.xml
def show
@user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @user }
end
end
# GET /users/new
# GET /users/new.xml
def new
@user = User.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @user }
end
end
# GET /users/1/edit
def edit
@user = User.find(params[:id])
end
# POST /users
# POST /users.xml
def create
@user = User.new(params[:user])
respond_to do |format|
if @user.save
format.html { redirect_to(users_url,
:notice => "User #{@user.name} was successfully created.") }
format.xml { render :xml => @user, :status => :created,
:location => @user }
else
format.html { render :action => "new" }
format.xml { render :xml => @user.errors,
:status => :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.xml
def update
@user = User.find(params[:id])
respond_to do |format|
if @user.update_attributes(params[:user])
format.html { redirect_to(users_url,
:notice => "User #{@user.name} was successfully updated.") }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @user.errors,
:status => :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.xml
def destroy
@user = User.find(params[:id])
begin
@user.destroy
flash[:notice] = "User #{@user.name} deleted"
rescue Exception => e
flash[:notice] = e.message
end
respond_to do |format|
format.html { redirect_to(users_url) }
format.xml { head :ok }
end
end
end
edit app\controllers\store_controller.rb
def find_cart
@cart = (session[:cart] ||= Cart.new)
end
edit app\controllers\store_controller.rb
before_filter :find_cart, :except => :empty_cart
echo "Product.new" | IRBRC=tmp\irbrc ruby script\rails console
Product.new | IRBRC=tmp\irbrc ruby script\rails console
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
# ...
ruby script\rails generate controller info who_bought
create app/controllers/info_controller.rb
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-02-25 15:48:29.105500
updated_at = 2010-02-25 15:48:29.105500
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-02-25 15:48:29.109500
updated_at = 2010-02-25 15:48:29.109500
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-02-25 15:48:29.113500
updated_at = 2010-02-25 15:48:29.113500
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-02-25 15:49:41.933500
updated_at = 2010-02-25 15:49:41.933500
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?1267112978" media="all" rel="stylesheet" type="text/css" />
<!-- END:stylesheet -->
<script src="/javascripts/prototype.js?1267112820" type="text/javascript"></script>
<script src="/javascripts/effects.js?1267112820" type="text/javascript"></script>
<script src="/javascripts/dragdrop.js?1267112820" type="text/javascript"></script>
<script src="/javascripts/controls.js?1267112820" type="text/javascript"></script>
<script src="/javascripts/rails.js?1267112820" type="text/javascript"></script>
<script src="/javascripts/application.js?1267112820" type="text/javascript"></script>
</head>
<!-- END:jit -->
<body id="store">
<div id="banner">
<img alt="Logo" src="/images/logo.png?1265052634" />
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>
<created-at type="datetime">2010-02-25T15:48:29Z</created-at>
<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></description>
<id type="integer">3</id>
<image-url>/images/svn.jpg</image-url>
<price type="decimal">28.5</price>
<title>Pragmatic Version Control</title>
<updated-at type="datetime">2010-02-25T15:48:29Z</updated-at>
<orders type="array">
<order>
<address>123 Main St</address>
<created-at type="datetime">2010-02-25T15:49:41Z</created-at>
<email>customer@example.com</email>
<id type="integer">1</id>
<name>Dave Thomas</name>
<pay-type>check</pay-type>
<updated-at type="datetime">2010-02-25T15:49:41Z</updated-at>
</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 rel="alternate" type="text/html" href="http://localhost:3000"/>
<link rel="self" type="application/atom+xml" href="http://localhost:3000/info/who_bought/3.atom"/>
<title>Who bought Pragmatic Version Control</title>
<updated>2010-02-25T15:49:41Z</updated>
<entry>
<id>tag:localhost,2005:Order/1</id>
<published>2010-02-25T15:49:41Z</published>
<updated>2010-02-25T15:49:41Z</updated>
<link rel="alternate" type="text/html" 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
{"orders":[{"name":"Dave Thomas","address":"123 Main St","created_at":"2010-02-25T15:49:41Z","updated_at":"2010-02-25T15:49:41Z","pay_type":"check","id":1,"email":"customer@example.com"}],"price":28.5,"created_at":"2010-02-25T15:48:29Z","title":"Pragmatic Version Control","image_url":"/images/svn.jpg","updated_at":"2010-02-25T15:48:29Z","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:
admin_controller.rb: c...
application_controller.rb: c.
info_controller.rb: c..
line_items_controller.rb: c.......
orders_controller.rb: c.......
products_controller.rb: c.......
store_controller.rb: c........
users_controller.rb: c.......
admin_helper.rb: m
application_helper.rb: m
info_helper.rb: m
line_items_helper.rb: m
orders_helper.rb: m
products_helper.rb: m
store_helper.rb: m.
users_helper.rb: m
cart.rb: c....
cart_item.rb: c....
line_item.rb: c.
order.rb: c.
product.rb: c..
user.rb: c.......
Generating HTML...
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
Files: 23
Classes: 14
Modules: 8
Methods: 62
Elapsed: 1.420s
rake stats
(in C:/cygwin/home/rubys/git/awdwr/work/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 | 204 | 162 | 7 | 0 | 0 | 0 |
| Unit tests | 60 | 45 | 11 | 0 | 0 | 0 |
+----------------------+-------+-------+---------+---------+-----+-------+
| Total | 1020 | 696 | 32 | 62 | 1 | 9 |
+----------------------+-------+-------+---------+---------+-----+-------+
Code LOC: 489 Test LOC: 207 Code to Test Ratio: 1:0.4
13 Task I: Internationalization
get /store/empty_cart
You are being
redirected .
get http://localhost:3000/store
Pragmatic Bookshelf
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
edit config\initializers\i18n.rb
#encoding: utf-8
I18n.default_locale = 'en'
LOCALES_DIRECTORY = "#{Rails.root}/config/locales/"
LANGUAGES = {
'English' => 'en',
"Espa\xc3\xb1ol" => 'es'
}
Restart the server.
edit app\views\layouts\store.html.erb
<% form_tag '', :method => 'GET', :class => 'locale' do %>
<%= select_tag 'locale', options_for_select(LANGUAGES, I18n.locale),
:onchange => 'this.form.submit()' %>
<%= submit_tag 'submit' %>
<%= javascript_tag "$$('.locale input').each(Element.hide)" %>
<% end %>
get /store?locale=en
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
edit app\controllers\application_controller.rb
class ApplicationController < ActionController::Base
layout "store"
#...
before_filter :authorize, :except => :login
before_filter :set_locale
protect_from_forgery
protected
def authorize
unless User.find_by_id(session[:user_id])
flash[:notice] = "Please log in"
redirect_to :controller => 'admin', :action => 'login'
end
end
def set_locale
session[:locale] = params[:locale] if params[:locale]
I18n.locale = session[:locale] || I18n.default_locale
locale_path = "#{LOCALES_DIRECTORY}#{I18n.locale}.yml"
unless I18n.load_path.include? locale_path
I18n.load_path << locale_path
I18n.backend.send(:init_translations)
end
rescue Exception => err
logger.error err
flash.now[:notice] = "#{I18n.locale} translation not available"
I18n.load_path -= [locale_path]
I18n.locale = session[:locale] = I18n.default_locale
end
end
edit public\stylesheets\depot.css
.locale {
float:right;
padding-top: 0.2em
}
get /store?locale=es
es translation not available
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
edit app\views\layouts\store.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Pragprog Books Online Store</title>
<%= stylesheet_link_tag "depot", :media => "all" %>
<%= javascript_include_tag :defaults %>
</head>
<body id="store">
<div id="banner">
<% form_tag '', :method => 'GET', :class => 'locale' do %>
<%= select_tag 'locale', options_for_select(LANGUAGES, I18n.locale),
:onchange => 'this.form.submit()' %>
<%= submit_tag 'submit' %>
<%= javascript_tag "$$('.locale input').each(Element.hide)" %>
<% end %>
<%= image_tag("logo.png") %>
<%= @page_title || I18n.t('layout.title') %>
</div>
<div id="columns">
<div id="side">
<% if @cart %>
<% hidden_div_if(@cart.items.empty?, :id => "cart") do %>
<%= render(:partial => "cart", :object => @cart) %>
<% end %>
<% end %>
<a href="http://www...."><%= I18n.t 'layout.side.home' %></a><br />
<a href="http://www..../faq"><%= I18n.t 'layout.side.questions' %></a><br />
<a href="http://www..../news"><%= I18n.t 'layout.side.news' %></a><br />
<a href="http://www..../contact"><%= I18n.t 'layout.side.contact' %></a><br />
<% if session[:user_id] %>
<br />
<%= link_to 'Orders', :controller => 'orders' %><br />
<%= link_to 'Products', :controller => 'products' %><br />
<%= link_to 'Users', :controller => 'users' %><br />
<br />
<%= link_to 'Logout', :controller => 'admin', :action => 'logout' %>
<% end %>
</div>
<div id="main">
<% if flash[:notice] -%>
<div id="notice"><%= flash[:notice] %></div>
<% end -%>
<%= yield :layout %>
</div>
</div>
</body>
</html>
edit config\locales\en.yml
en:
number:
currency:
format:
unit: "$"
precision: 2
separator: "."
delimiter: ","
format: "%u%n"
layout:
title: "Pragmatic Bookshelf"
side:
home: "Home"
questions: "Questions"
news: "News"
contact: "Contact"
cart:
title: "Your Cart"
button:
empty: "Empty cart"
checkout: "Checkout"
main:
title: "Your Pragmatic Catalog"
button:
add: "Add to Cart"
checkout:
legend: "Please Enter your Details"
name: "Name"
address: "Address"
email: "E-mail"
pay_type: "Pay with"
pay_prompt: "Select a payment method"
submit: "Place Order"
flash:
thanks: "Thank you for your order"
edit config\locales\es.yml
es:
number:
currency:
format:
unit: "$US"
precision: 2
separator: ","
delimiter: "."
format: "%n %u"
activerecord:
models:
order: "pedido"
attributes:
order:
address: "Dirección"
name: "Nombre"
email: "E-mail"
pay_type: "Forma de pago"
errors:
messages:
inclusion: "no está incluido en la lista"
blank: "no puede quedar en blanco"
errors:
template:
body: "Hay problemas con los siguientes campos:"
header:
one: "1 error ha impedido que este {{model}} se guarde"
other: "{{count}} errores han impedido que este {{model}} se guarde"
layout:
title: "Publicaciones de Pragmatic"
side:
home: "Inicio"
questions: "Preguntas"
news: "Noticias"
contact: "Contacto"
cart:
title: "Carrito de la Compra"
button:
empty: "Vaciar Carrito"
checkout: "Comprar"
main:
title: "Su Catálogo de Pragmatic"
button:
add: "Añadir al Carrito"
checkout:
legend: "Por favor, introduzca sus datos"
name: "Nombre"
address: "Dirección"
email: "E-mail"
pay_type: "Pagar con"
pay_prompt: "Seleccione un m\xC3\xA9todo de pago"
submit: "Realizar Pedido"
flash:
thanks: "Gracias por su pedido"
get /store?locale=es
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
edit app\views\store\index.html.erb
<h1><%=raw I18n.t('main.title') %></h1>
<% @products.each do |product| -%>
<div class="entry">
<%= image_tag(product.image_url) %>
<h3><%=h product.title %></h3>
<%=raw product.description %>
<div class="price-line">
<span class="price"><%=raw number_to_currency(product.price) %></span>
<% form_tag({:action=>'add_to_cart', :id=>product}, :remote=>true) do %>
<%= submit_tag I18n.t('main.button.add') %>
<% end %>
</div>
</div>
<% end %>
edit app\views\store\_cart.html.erb
<div class="cart-title">Your Cart</div>
<table>
<%= render(:partial => "cart_item", :collection => cart.items) %>
<tr class="total-line">
<td colspan="2">Total</td>
<td class="total-cell"><%=raw number_to_currency(cart.total_price) %></td>
</tr>
</table>
<%= button_to "Checkout", :action => 'checkout' %>
<%= button_to "Empty cart", :action => :empty_cart %>
edit app\views\store\_cart_item.html.erb
<% if cart_item == @current_item %>
<tr id="current_item">
<% else %>
<tr>
<% end %>
<td><%= cart_item.quantity %>×</td>
<td><%= cart_item.title %></td>
<td class="item-price"><%=raw number_to_currency(cart_item.price) %></td>
</tr>
get /store?locale=es
Su Catálogo de Pragmatic
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
edit app\views\store\_cart.html.erb
<div class="cart-title"><%= I18n.t 'layout.cart.title' %></div>
<table>
<%= render(:partial => "cart_item", :collection => cart.items) %>
<tr class="total-line">
<td colspan="2">Total</td>
<td class="total-cell"><%=raw number_to_currency(cart.total_price) %></td>
</tr>
</table>
<%= button_to I18n.t('layout.cart.button.checkout'), :action => 'checkout' %>
<%= button_to I18n.t('layout.cart.button.empty'), :action => :empty_cart %>
get /store/add_to_cart/2
You are being
redirected .
get http://localhost:3000/store
Su Catálogo de Pragmatic
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
edit app\views\store\checkout.html.erb
<div class="depot-form">
<%= error_messages_for 'order' %>
<% form_for :order, :url => { :action => :save_order } do |form| %>
<fieldset>
<legend><%= I18n.t 'checkout.legend' %></legend>
<div>
<%= form.label :name, I18n.t('checkout.name') + ":" %>
<%= form.text_field :name, :size => 40 %>
</div>
<div>
<%= form.label :address, I18n.t('checkout.address') + ":" %>
<%= form.text_area :address, :rows => 3, :cols => 40 %>
</div>
<div>
<%= form.label :email, I18n.t('checkout.email') + ":" %>
<%= form.text_field :email, :size => 40 %>
</div>
<div>
<%= form.label :pay_type, I18n.t('checkout.pay_type') + ":" %>
<%=
form.select :pay_type,
Order::PAYMENT_TYPES,
:prompt => I18n.t('checkout.pay_prompt')
%>
</div>
<%= submit_tag I18n.t('checkout.submit'), :class => "submit" %>
</fieldset>
<% end %>
</div>
edit app\controllers\store_controller.rb
class StoreController < ApplicationController
before_filter :find_cart, :except => :empty_cart
def index
@products = Product.find_products_for_sale
end
def add_to_cart
product = Product.find(params[:id])
@current_item = @cart.add_product(product)
respond_to do |format|
format.js if request.xhr?
format.html {redirect_to_index}
end
rescue ActiveRecord::RecordNotFound
logger.error("Attempt to access invalid product #{params[:id]}")
redirect_to_index("Invalid product")
end
def checkout
if @cart.items.empty?
redirect_to_index("Your cart is empty")
else
@order = Order.new
end
end
def save_order
@order = Order.new(params[:order])
@order.add_line_items_from_cart(@cart)
if @order.save
session[:cart] = nil
redirect_to_index(I18n.t('flash.thanks'))
else
render :action => 'checkout'
end
end
def empty_cart
session[:cart] = nil
redirect_to_index
end
private
def redirect_to_index(msg = nil)
flash[:notice] = msg if msg
redirect_to :action => 'index'
end
def find_cart
@cart = (session[:cart] ||= Cart.new)
end
#...
protected
def authorize
end
end
get /store?locale=es
Su Catálogo de Pragmatic
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
get /store/add_to_cart/2
You are being
redirected .
get http://localhost:3000/store
Su Catálogo de Pragmatic
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
get /store/checkout
get /store/save_order
get /store/save_order
post /store/save_order
order[pay_type] => check
order[address] => 123 Main St., Anytown USA
order[email] => juser@hotmail.com
order[name] => Joe User
You are being
redirected .
get http://localhost:3000/store
Gracias por su pedido
Su Catálogo de Pragmatic
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
get /store?locale=en
Your Pragmatic Catalog
Pragmatic Project Automation
Pragmatic Project Automation shows you how to improve the
consistency and repeatability of your project's procedures using
automation to reduce risk and errors.
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.
Pragmatic Unit Testing (C#)
Pragmatic programmers use feedback to drive their development and
personal processes. The most valuable feedback you can get while
coding comes from unit testing.
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.
Pragmatic Version Control
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.
14.1 Tests Baked Right In
dir/w test
Volume in drive C is ACER
Volume Serial Number is 0412-C06E
Directory of C:\cygwin\home\rubys\git\awdwr\work\depot\test
[.] [..] [fixtures] [functional]
[integration] [performance] test_helper.rb [unit]
1 File(s) 454 bytes
7 Dir(s) 99,147,886,592 bytes free
dir test\unit
helpers line_item_test.rb order_test.rb product_test.rb user_test.rb
dir test\functional
admin_controller_test.rb products_controller_test.rb
info_controller_test.rb store_controller_test.rb
line_items_controller_test.rb users_controller_test.rb
orders_controller_test.rb
14.2 Unit Testing of Models
type test\unit\product_test.rb
require 'test_helper'
class ProductTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
end
ruby -Itest test\unit\product_test.rb
Loaded suite test/unit/product_test
Started
E
Finished in 0.23 seconds.
1) Error:
test_the_truth(ProductTest):
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: users: DELETE FROM "users" WHERE 1=1
1 tests, 0 assertions, 0 failures, 1 errors
rake db:test:prepare
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
ruby -Itest test\unit\product_test.rb
Loaded suite test/unit/product_test
Started
.
Finished in 0.25 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
rake test:units
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
Loaded suite C:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
....
Finished in 0.28 seconds.
4 tests, 4 assertions, 0 failures, 0 errors
edit test\unit\product_test.rb
require 'test_helper'
class ProductTest < ActiveSupport::TestCase
fixtures :products
# Replace this with your real tests.
test "the truth" do
assert true
end
test "invalid with empty attributes" do
product = Product.new
assert !product.valid?
assert product.errors[:title].any?
assert product.errors[:description].any?
assert product.errors[:price].any?
assert product.errors[:image_url].any?
end
test "positive price" do
product = Product.new(:title => "My Book Title",
:description => "yyy",
:image_url => "zzz.jpg")
product.price = -1
assert !product.valid?
assert_equal "should be at least 0.01", product.errors[:price].join
product.price = 0
assert !product.valid?
assert_equal "should be at least 0.01", product.errors[:price].join
product.price = 1
assert product.valid?
end
test "image url" do
ok = %w{ fred.gif fred.jpg fred.png FRED.JPG FRED.Jpg
http://a.b.c/x/y/z/fred.gif }
bad = %w{ fred.doc fred.gif/more fred.gif.more }
ok.each do |name|
product = Product.new(:title => "My Book Title",
:description => "yyy",
:price => 1,
:image_url => name)
assert product.valid?, product.errors.full_messages
end
bad.each do |name|
product = Product.new(:title => "My Book Title",
:description => "yyy",
:price => 1,
:image_url => name)
assert !product.valid?, "saving #{name}"
end
end
test "unique title" do
product = Product.new(:title => products(:ruby_book).title,
:description => "yyy",
:price => 1,
:image_url => "fred.gif")
assert !product.save
assert_equal "has already been taken", product.errors[:title].join
end
test "unique title1" do
product = Product.new(:title => products(:ruby_book).title,
:description => "yyy",
:price => 1,
:image_url => "fred.gif")
assert !product.save
assert_equal I18n.translate('activerecord.errors.messages.taken'),
product.errors[:title].join
end
end
edit test\fixtures\products.yml
ruby_book:
title: Programming Ruby
description: Dummy description
price: 1234
image_url: ruby.png
rails_book:
title: Agile Web Development with Rails
description: Dummy description
price: 2345
image_url: rails.png
rake test:units
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
Loaded suite C:/ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
.........
Finished in 0.36 seconds.
9 tests, 27 assertions, 0 failures, 0 errors
edit test\unit\cart_test.rb
require 'test_helper'
class CartTest < ActiveSupport::TestCase
fixtures :products
test "add unique products" do
cart = Cart.new
rails_book = products(:rails_book)
ruby_book = products(:ruby_book)
cart.add_product rails_book
cart.add_product ruby_book
assert_equal 2, cart.items.size
assert_equal rails_book.price + ruby_book.price, cart.total_price
end
test "add_duplicate_product" do
cart = Cart.new
rails_book = products(:rails_book)
cart.add_product rails_book
cart.add_product rails_book
assert_equal 2*rails_book.price, cart.total_price
assert_equal 1, cart.items.size
assert_equal 2, cart.items[0].quantity
end
end
ruby -I test test\unit\cart_test.rb
Loaded suite test/unit/cart_test
Started
..
Finished in 0.27 seconds.
2 tests, 5 assertions, 0 failures, 0 errors
edit test\unit\cart_test1.rb
require 'test_helper'
class CartTest < ActiveSupport::TestCase
fixtures :products
def setup
@cart = Cart.new
@rails = products(:rails_book)
@ruby = products(:ruby_book)
end
test "add unique products" do
@cart.add_product @rails
@cart.add_product @ruby
assert_equal 2, @cart.items.size
assert_equal @rails.price + @ruby.price, @cart.total_price
end
test "add duplicate product" do
@cart.add_product @rails
@cart.add_product @rails
assert_equal 2*@rails.price, @cart.total_price
assert_equal 1, @cart.items.size
assert_equal 2, @cart.items[0].quantity
end
end
ruby -I test test\unit\cart_test1.rb
Loaded suite test/unit/cart_test1
Started
..
Finished in 0.27 seconds.
2 tests, 5 assertions, 0 failures, 0 errors
14.3 Functional Testing of Controllers
edit app\controllers\application_controller.rb
class ApplicationController < ActionController::Base
layout "store"
before_filter :authorize, :except => :login
#...
protected
def authorize
unless User.find_by_id(session[:user_id])
flash[:notice] = "Please log in"
redirect_to :controller => 'admin', :action => 'login'
end
end
def set_locale
session[:locale] = params[:locale] if params[:locale]
I18n.locale = session[:locale] || I18n.default_locale
locale_path = "#{LOCALES_DIRECTORY}#{I18n.locale}.yml"
unless I18n.load_path.include? locale_path
I18n.load_path << locale_path
I18n.backend.send(:init_translations)
end
rescue Exception => err
logger.error err
flash.now[:notice] = "#{I18n.locale} translation not available"
I18n.load_path -= [locale_path]
I18n.locale = session[:locale] = I18n.default_locale
end
end
edit test\functional\admin_controller_test.rb
require 'test_helper'
class AdminControllerTest < ActionController::TestCase
fixtures :users
# Replace this with your real tests.
test "the truth" do
assert true
end
if false
test "index" do
get :index
assert_response :success
end
end
test "index without user" do
get :index
assert_redirected_to :action => "login"
assert_equal "Please log in", flash[:notice]
end
test "index with user" do
get :index, {}, { :user_id => users(:dave).id }
assert_response :success
assert_template "index"
end
test "login" do
dave = users(:dave)
post :login, :name => dave.name, :password => 'secret'
assert_redirected_to :action => "index"
assert_equal dave.id, session[:user_id]
end
test "bad password" do
dave = users(:dave)
post :login, :name => dave.name, :password => 'wrong'
assert_template "login"
end
end
edit test\fixtures\users.yml
<% SALT = "NaCl" unless defined?(SALT) %>
dave:
name: dave
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('secret', SALT) %>
ruby -I test test\functional\admin_controller_test.rb
Loaded suite test/functional/admin_controller_test
Started
.....
Finished in 0.35 seconds.
5 tests, 8 assertions, 0 failures, 0 errors
14.4 Integration Testing of Applications
ruby script\rails generate integration_test user_stories
invoke test_unit
create test/integration/user_stories_test.rb
edit test\integration\user_stories_test.rb
require 'test_helper'
class UserStoriesTest < ActionController::IntegrationTest
fixtures :products
# A user goes to the index page. They select a product, adding it to their
# cart, and check out, filling in their details on the checkout form. When
# they submit, an order is created containing their information, along with a
# single line item corresponding to the product they added to their cart.
test "buying a product" do
LineItem.delete_all
Order.delete_all
ruby_book = products(:ruby_book)
get "/store/index"
assert_response :success
assert_template "index"
xml_http_request :put, "/store/add_to_cart/#{ruby_book.id}"
assert_response :success
cart = session[:cart]
assert_equal 1, cart.items.size
assert_equal ruby_book, cart.items[0].product
post "/store/checkout"
assert_response :success
assert_template "checkout"
post_via_redirect "/store/save_order",
:order => { :name => "Dave Thomas",
:address => "123 The Street",
:email => "dave@example.com",
:pay_type => "check" }
assert_response :success
assert_template "index"
assert_equal 0, session[:cart].items.size
orders = Order.find(:all)
assert_equal 1, orders.size
order = orders[0]
assert_equal "Dave Thomas", order.name
assert_equal "123 The Street", order.address
assert_equal "dave@example.com", order.email
assert_equal "check", order.pay_type
assert_equal 1, order.line_items.size
line_item = order.line_items[0]
assert_equal ruby_book, line_item.product
end
end
ruby -I test test\integration\user_stories_test.rb
Loaded suite test/integration/user_stories_test
Started
.
Finished in 0.54 seconds.
1 tests, 17 assertions, 0 failures, 0 errors
edit test\integration\dsl_user_stories_test.rb
require 'test_helper'
class DslUserStoriesTest < ActionController::IntegrationTest
fixtures :products
DAVES_DETAILS = {
:name => "Dave Thomas",
:address => "123 The Street",
:email => "dave@example.com",
:pay_type => "check"
}
MIKES_DETAILS = {
:name => "Mike Clark",
:address => "345 The Avenue",
:email => "mike@pragmaticstudio.com",
:pay_type => "cc"
}
def setup
LineItem.delete_all
Order.delete_all
@ruby_book = products(:ruby_book)
@rails_book = products(:rails_book)
end
# A user goes to the store index page. They select a product,
# adding it to their cart. They then check out, filling in
# their details on the checkout form. When they submit,
# an order is created in the database containing
# their information, along with a single line item
# corresponding to the product they added to their cart.
def test_buying_a_product
dave = regular_user
dave.get "/store/index"
dave.is_viewing "index"
dave.buys_a @ruby_book
dave.has_a_cart_containing @ruby_book
dave.checks_out DAVES_DETAILS
dave.is_viewing "index"
check_for_order DAVES_DETAILS, @ruby_book
end
def test_two_people_buying
dave = regular_user
mike = regular_user
dave.buys_a @ruby_book
mike.buys_a @rails_book
dave.has_a_cart_containing @ruby_book
dave.checks_out DAVES_DETAILS
mike.has_a_cart_containing @rails_book
check_for_order DAVES_DETAILS, @ruby_book
mike.checks_out MIKES_DETAILS
check_for_order MIKES_DETAILS, @rails_book
end
def regular_user
open_session do |user|
def user.is_viewing(page)
assert_response :success
assert_template page
end
def user.buys_a(product)
xml_http_request :put, "/store/add_to_cart/#{product.id}"
assert_response :success
end
def user.has_a_cart_containing(*products)
cart = session[:cart]
assert_equal products.size, cart.items.size
for item in cart.items
assert products.include?(item.product)
end
end
def user.checks_out(details)
post "/store/checkout"
assert_response :success
assert_template "checkout"
post_via_redirect "/store/save_order",
:order => { :name => details[:name],
:address => details[:address],
:email => details[:email],
:pay_type => details[:pay_type]
}
assert_response :success
assert_template "index"
assert_equal 0, session[:cart].items.size
end
end
end
def check_for_order(details, *products)
order = Order.find_by_name(details[:name])
assert_not_nil order
assert_equal details[:name], order.name
assert_equal details[:address], order.address
assert_equal details[:email], order.email
assert_equal details[:pay_type], order.pay_type
assert_equal products.size, order.line_items.size
for line_item in order.line_items
assert products.include?(line_item.product)
end
end
end
ruby -I test test\integration\dsl_user_stories_test.rb
Loaded suite test/integration/dsl_user_stories_test
Started
..
Finished in 0.68 seconds.
2 tests, 49 assertions, 0 failures, 0 errors
14.5 Performance Testing
mkdir test\fixtures\performance\
edit test\fixtures\performance\products.yml
<% 1.upto(1000) do |i| %>
product_<%= i %>:
id: <%= i %>
title: Product Number <%= i %>
description: My description
image_url: product.gif
price: 1234
<% end %>
edit test\performance\order_speed_test.rb
require 'test_helper'
require 'store_controller'
class OrderSpeedTest < ActionController::TestCase
tests StoreController
DAVES_DETAILS = {
:name => "Dave Thomas",
:address => "123 The Street",
:email => "dave@example.com",
:pay_type => "check"
}
self.fixture_path = File.join(File.dirname(__FILE__), "../fixtures/performance")
fixtures :products
def test_100_orders
Order.delete_all
LineItem.delete_all
@controller.logger.silence do
elapsed_time = Benchmark.realtime do
100.downto(1) do |prd_id|
cart = Cart.new
cart.add_product(Product.find(prd_id))
post :save_order,
{ :order => DAVES_DETAILS },
{ :cart => cart }
assert_redirected_to :action => :index
end
end
assert_equal 100, Order.count
assert elapsed_time < 3.00
end
end
end
ruby -I test test\performance\order_speed_test.rb
Loaded suite test/performance/order_speed_test
Started
.
Finished in 2.07 seconds.
1 tests, 102 assertions, 0 failures, 0 errors
edit app\models\user.rb
require 'digest/sha1'
class User < ActiveRecord::Base
validates_presence_of :name
validates_uniqueness_of :name
attr_accessor :password_confirmation
validates_confirmation_of :password
validate :password_non_blank
def self.authenticate(name, password)
user = self.find_by_name(name)
if user
expected_password = encrypted_password(password, user.salt)
if user.hashed_password != expected_password
user = nil
end
end
user
end
# 'password' is a virtual attribute
def password
@password
end
def password=(pwd)
@password = pwd
return if pwd.blank?
create_new_salt
self.hashed_password = User.encrypted_password(self.password, self.salt)
end
after_destroy :ensure_an_admin_remains
def ensure_an_admin_remains
if User.count.zero?
raise "Can't delete last user"
end
end
private
def password_non_blank
errors.add(:password, "Missing password") if hashed_password.blank?
end
def create_new_salt
self.salt = self.object_id.to_s + rand.to_s
end
def self.encrypted_password(password, salt)
100000.times { Math.sin(1)}
string_to_hash = password + "wibble" + salt
Digest::SHA1.hexdigest(string_to_hash)
end
end
ruby script\rails benchmarker "User.encrypted_password(\"secret\", \"salt\")"
user system total real
#1 0.172000 0.000000 0.172000 ( 0.166000)
ruby script\rails profiler "User.encrypted_password(\"secret\", \"salt\")"
Using the standard Ruby profiler.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
63.27 3.12 3.12 1 3119.00 4524.00 Integer#times
28.50 4.52 1.40 100000 0.01 0.01 Math.sin
1.58 4.60 0.08 70 1.11 10.49 Array#each
1.56 4.68 0.08 288 0.27 0.27 Pathname#chop_basename
0.65 4.71 0.03 11 2.91 15.64 Array#map
0.63 4.74 0.03 7 4.43 17.71 Pathname#relative_path_from
0.32 4.76 0.02 4 4.00 8.00 Array#select
0.32 4.77 0.02 172 0.09 0.09 Array#[]
0.32 4.79 0.02 480 0.03 0.03 Kernel.==
0.32 4.81 0.02 1 16.00 16.00 ActiveSupport::Dependencies.qualified_name_for
0.32 4.82 0.02 832 0.02 0.02 Hash#key?
0.32 4.84 0.02 8 2.00 2.00 Pathname#expand_path
0.32 4.85 0.02 8 2.00 3.87 ActiveRecord::Base#_update_validate_superclass_callbacks
0.32 4.87 0.02 14 1.14 4.43 Pathname#cleanpath_aggressive
0.30 4.88 0.02 97 0.15 0.15 Symbol#to_s
0.30 4.90 0.01 822 0.02 0.02 String#==
0.30 4.91 0.01 44 0.34 0.34 Class#superclass
0.30 4.93 0.01 833 0.02 0.02 String#to_s
0.00 4.93 0.00 3 0.00 0.00 Module#define_method
0.00 4.93 0.00 16 0.00 0.00 Array#compact
0.00 4.93 0.00 7 0.00 0.00 Array#pop
0.00 4.93 0.00 1 0.00 406.00 ActiveSupport::Dependencies.load_missing_constant
0.00 4.93 0.00 1 0.00 16.00 ActiveModel::Validations::ClassMethods.validates_presence_of
0.00 4.93 0.00 260 0.00 0.00 String#rindex
0.00 4.93 0.00 1 0.00 0.00 Class#inherited
0.00 4.93 0.00 1 0.00 0.00 TrueClass#duplicable?
0.00 4.93 0.00 5 0.00 0.00 Symbol#inspect
0.00 4.93 0.00 30 0.00 0.00 String#+
0.00 4.93 0.00 2 0.00 0.00 Class#inheritable_attributes
0.00 4.93 0.00 2 0.00 0.00 ActiveSupport::Dependencies::WatchStack#concat
0.00 4.93 0.00 1 0.00 0.00 String#tr
0.00 4.93 0.00 2 0.00 0.00 ActiveSupport::Dependencies.autoloaded_constants
0.00 4.93 0.00 5 0.00 15.60 ActiveSupport::Callbacks::ClassMethods.__define_runner
0.00 4.93 0.00 9 0.00 0.00 Kernel.nil?
0.00 4.93 0.00 51 0.00 0.00 Array#<<
0.00 4.93 0.00 4 0.00 0.00 Hash#merge
0.00 4.93 0.00 1 0.00 218.00 Kernel.load
0.00 4.93 0.00 2 0.00 0.00 Array#assoc
0.00 4.93 0.00 5 0.00 0.00 Module#method_defined?
0.00 4.93 0.00 1 0.00 406.00 ActiveSupport::Dependencies::ModuleConstMissing.const_missing
0.00 4.93 0.00 24 0.00 0.00 Module#const_get
0.00 4.93 0.00 260 0.00 0.00 Kernel.===
0.00 4.93 0.00 3 0.00 0.00 ActiveSupport::Dependencies.to_constant_name
0.00 4.93 0.00 7 0.00 0.00 Array#extract_options!
0.00 4.93 0.00 3 0.00 0.00 ActiveModel::EachValidator#initialize
0.00 4.93 0.00 3 0.00 0.00 ActiveModel::Validations::ClassMethods._merge_attributes
0.00 4.93 0.00 1 0.00 0.00 ActiveSupport::Dependencies.search_for_file
0.00 4.93 0.00 13 0.00 0.00 Module#class_eval
0.00 4.93 0.00 3 0.00 0.00 ActiveSupport::Dependencies.loaded
0.00 4.93 0.00 24 0.00 0.00 File#join
0.00 4.93 0.00 6 0.00 0.00 ActiveSupport::Dependencies.constant_watch_stack
0.00 4.93 0.00 303 0.00 0.00 Regexp#to_s
0.00 4.93 0.00 2 0.00 7.50 Array#delete
0.00 4.93 0.00 1 0.00 0.00 Symbol#===
0.00 4.93 0.00 10 0.00 0.00 Hash#initialize_copy
0.00 4.93 0.00 6 0.00 0.00 String#sub
0.00 4.93 0.00 1 0.00 0.00 String#downcase
0.00 4.93 0.00 2 0.00 0.00 Mutex#synchronize
0.00 4.93 0.00 25 0.00 0.00 Module#method_added
0.00 4.93 0.00 2 0.00 0.00 ActiveSupport::Dependencies::WatchStack#get
0.00 4.93 0.00 11 0.00 0.00 ActiveRecord::Base#respond_to?
0.00 4.93 0.00 1 0.00 390.00 ActiveSupport::Dependencies.require_or_load
0.00 4.93 0.00 125 0.00 0.00 Array#first
0.00 4.93 0.00 20 0.00 0.00 Fixnum#+
0.00 4.93 0.00 261 0.00 0.00 String#[]
0.00 4.93 0.00 22 0.00 0.00 Kernel.is_a?
0.00 4.93 0.00 68 0.00 0.00 Class#new
0.00 4.93 0.00 5 0.00 0.00 Hash#update
0.00 4.93 0.00 1 0.00 0.00 String#constantize
0.00 4.93 0.00 4 0.00 27.50 Module#local_constants
0.00 4.93 0.00 7 0.00 0.00 Array#initialize_copy
0.00 4.93 0.00 5 0.00 0.00 Array#map!
0.00 4.93 0.00 2 0.00 0.00 Proc#call
0.00 4.93 0.00 24 0.00 0.00 Array#wrap
0.00 4.93 0.00 3 0.00 0.00 Array#blank?
0.00 4.93 0.00 14 0.00 0.00 File#dirname
0.00 4.93 0.00 4 0.00 0.00 Object#presence
0.00 4.93 0.00 2 0.00 0.00 Array#to_ary
0.00 4.93 0.00 3 0.00 0.00 ActiveModel::Validator#initialize
0.00 4.93 0.00 8 0.00 0.00 Object#duplicable?
0.00 4.93 0.00 1 0.00 0.00 Array#uniq
0.00 4.93 0.00 11 0.00 0.00 String#split
0.00 4.93 0.00 1 0.00 0.00 ActiveRecord::Base#inherited
0.00 4.93 0.00 1 0.00 0.00 ActiveSupport::Inflector.underscore
0.00 4.93 0.00 78 0.00 0.00 Kernel.respond_to?
0.00 4.93 0.00 1 0.00 0.00 NilClass#to_a
0.00 4.93 0.00 32 0.00 0.97 Kernel.send
0.00 4.93 0.00 20 0.00 0.00 NilClass#nil?
0.00 4.93 0.00 2 0.00 0.00 Hash#include?
0.00 4.93 0.00 23 0.00 0.00 Array#-
0.00 4.93 0.00 11 0.00 0.00 ActiveRecord::DynamicScopeMatch#initialize
0.00 4.93 0.00 21 0.00 0.00 Pathname#to_s
0.00 4.93 0.00 11 0.00 0.00 ActiveRecord::DynamicFinderMatch#match
0.00 4.93 0.00 5 0.00 0.00 Array#concat
0.00 4.93 0.00 1 0.00 0.00 Kernel.instance_variable_set
0.00 4.93 0.00 2 0.00 16.00 ActiveSupport::Dependencies::WatchStack#new_constants_for
0.00 4.93 0.00 2 0.00 0.00 ActiveSupport::Dependencies.load?
0.00 4.93 0.00 4 0.00 0.00 Module#ancestors
0.00 4.93 0.00 5 0.00 0.00 Array#delete_if
0.00 4.93 0.00 9 0.00 0.00 ActiveSupport::Dependencies.logger
0.00 4.93 0.00 1 0.00 0.00 Observable.notify_observers
0.00 4.93 0.00 1 0.00 0.00 Array#uniq!
0.00 4.93 0.00 5 0.00 15.60 ActiveSupport::Callbacks::ClassMethods.set_callback
0.00 4.93 0.00 5 0.00 0.00 Kernel.silence_warnings
0.00 4.93 0.00 3 0.00 0.00 ActiveModel::EachValidator#check_validity!
0.00 4.93 0.00 10 0.00 0.00 File#expand_path
0.00 4.93 0.00 4 0.00 0.00 ActiveRecord::Base#_destroy_superclass_callbacks
0.00 4.93 0.00 25 0.00 0.00 ActiveRecord::Base#_validate_callbacks
0.00 4.93 0.00 25 0.00 0.00 ActiveRecord::Callbacks::ClassMethods.method_added
0.00 4.93 0.00 71 0.00 0.00 Kernel.dup
0.00 4.93 0.00 5 0.00 3.20 Array#reverse_each
0.00 4.93 0.00 37 0.00 0.00 Kernel.__send__
0.00 4.93 0.00 1 0.00 0.00 String#scan
0.00 4.93 0.00 1 0.00 15.00 ActiveModel::Validations::ClassMethods.validates_confirmation_of
0.00 4.93 0.00 33 0.00 0.00 Kernel.hash
0.00 4.93 0.00 11 0.00 0.00 ActiveRecord::DynamicFinderMatch#initialize
0.00 4.93 0.00 5 0.00 0.00 Kernel.block_given?
0.00 4.93 0.00 4 0.00 39.25 Module#local_constant_names
0.00 4.93 0.00 12 0.00 0.00 ActiveSupport::Callbacks::Callback#next_id
0.00 4.93 0.00 2 0.00 0.00 ActiveRecord::Base#_update_destroy_superclass_callbacks
0.00 4.93 0.00 8 0.00 0.00 Hash#delete
0.00 4.93 0.00 1 0.00 140.00 ActiveSupport::Dependencies.loadable_constants_for_path
0.00 4.93 0.00 2 0.00 62.50 ActiveSupport::Dependencies::WatchStack#add_modules
0.00 4.93 0.00 37 0.00 0.00 Kernel.tainted?
0.00 4.93 0.00 4 0.00 0.00 ActiveSupport::Dependencies.log
0.00 4.93 0.00 11 0.00 0.00 ActiveRecord::DynamicScopeMatch#match
0.00 4.93 0.00 2 0.00 0.00 ActiveSupport::Dependencies.mechanism
0.00 4.93 0.00 28 0.00 0.00 Module#==
0.00 4.93 0.00 2 0.00 0.00 ActiveSupport::Dependencies.load_paths
0.00 4.93 0.00 1 0.00 0.00 String#camelize
0.00 4.93 0.00 1 0.00 0.00 ActiveSupport::Dependencies.history
0.00 4.93 0.00 28 0.00 0.00 Module#constants
0.00 4.93 0.00 1 0.00 15.00 ActiveRecord::Base#after_destroy
0.00 4.93 0.00 4 0.00 0.00 ActiveRecord::Base#_removed_destroy_callbacks
0.00 4.93 0.00 39 0.00 0.00 Hash#[]=
0.00 4.93 0.00 16 0.00 0.94 ActiveRecord::Base#_validate_superclass_callbacks
0.00 4.93 0.00 2 0.00 0.00 Kernel.equal?
0.00 4.93 0.00 2 0.00 15.00 Array#==
0.00 4.93 0.00 1 0.00 0.00 Kernel.require
0.00 4.93 0.00 5 0.00 0.00 ActiveSupport::Dependencies.qualified_const_defined?
0.00 4.93 0.00 157 0.00 0.00 Array#empty?
0.00 4.93 0.00 1 0.00 0.00 Digest::Base#finish
0.00 4.93 0.00 5 0.00 0.00 String#gsub
0.00 4.93 0.00 9 0.00 0.00 Array#push
0.00 4.93 0.00 1 0.00 0.00 String#underscore
0.00 4.93 0.00 1 0.00 0.00 Hash#each
0.00 4.93 0.00 2 0.00 0.00 Set#include?
0.00 4.93 0.00 2 0.00 0.00 Set#<<
0.00 4.93 0.00 37 0.00 0.00 Pathname#initialize
0.00 4.93 0.00 1 0.00 0.00 Object#initialize
0.00 4.93 0.00 1 0.00 0.00 Array#flatten
0.00 4.93 0.00 53 0.00 0.00 Fixnum#==
0.00 4.93 0.00 103 0.00 0.00 Array#shift
0.00 4.93 0.00 10 0.00 0.00 ActiveSupport::Callbacks::Callback#_compile_options
0.00 4.93 0.00 2 0.00 0.00 Kernel.singleton_method_added
0.00 4.93 0.00 16 0.00 0.00 Array#last
0.00 4.93 0.00 1 0.00 140.00 ActiveSupport::Dependencies::Loadable.load_dependency
0.00 4.93 0.00 1 0.00 16.00 ActiveRecord::Validations::ClassMethods.validates_uniqueness_of
0.00 4.93 0.00 1 0.00 0.00 ActiveSupport::Dependencies.load_once_path?
0.00 4.93 0.00 7 0.00 0.00 Array#fill
0.00 4.93 0.00 3 0.00 0.00 ActiveSupport::Callbacks::Callback#_normalize_legacy_filter
0.00 4.93 0.00 1 0.00 0.00 Observable.changed
0.00 4.93 0.00 3 0.00 0.00 File#file?
0.00 4.93 0.00 5 0.00 0.00 ActiveSupport::Callbacks::Callback#normalize_options!
0.00 4.93 0.00 28 0.00 0.00 Pathname#taint
0.00 4.93 0.00 28 0.00 0.00 Symbol#to_sym
0.00 4.93 0.00 7 0.00 20.00 Enumerable.inject
0.00 4.93 0.00 20 0.00 0.00 String#empty?
0.00 4.93 0.00 1 0.00 140.00 ActiveSupport::Dependencies::Loadable.require
0.00 4.93 0.00 28 0.00 0.00 Module#===
0.00 4.93 0.00 1 0.00 0.00 ActiveModel::Validations::ConfirmationValidator#setup
0.00 4.93 0.00 3 0.00 15.67 ActiveModel::Validations::ClassMethods.validates_with
0.00 4.93 0.00 57 0.00 0.00 Kernel.object_id
0.00 4.93 0.00 1 0.00 0.00 ActiveSupport::Inflector.camelize
0.00 4.93 0.00 17 0.00 0.00 Array#+
0.00 4.93 0.00 13 0.00 0.00 Module#const_defined?
0.00 4.93 0.00 1 0.00 0.00 ActiveSupport::Dependencies.warnings_on_first_load
0.00 4.93 0.00 58 0.00 0.00 String#initialize_copy
0.00 4.93 0.00 1 0.00 0.00 Digest::Instance.digest
0.00 4.93 0.00 14 0.00 0.00 Pathname#prepend_prefix
0.00 4.93 0.00 2 0.00 195.00 ActiveSupport::Dependencies.new_constants_in
0.00 4.93 0.00 1 0.00 0.00 Array#collect
0.00 4.93 0.00 1 0.00 0.00 Digest::Base#update
0.00 4.93 0.00 7 0.00 0.00 ActiveSupport::Callbacks::Callback#_compile_filter
0.00 4.93 0.00 5 0.00 0.00 Module#name
0.00 4.93 0.00 5 0.00 0.00 NilClass#to_s
0.00 4.93 0.00 3 0.00 0.00 Array#*
0.00 4.93 0.00 1 0.00 0.00 Hash#reverse_merge
0.00 4.93 0.00 21 0.00 0.00 Array#join
0.00 4.93 0.00 2 0.00 0.00 ActiveSupport::Dependencies::WatchStack#lock
0.00 4.93 0.00 31 0.00 0.00 Hash#default
0.00 4.93 0.00 1 0.00 0.00 String#upcase
0.00 4.93 0.00 11 0.00 1.45 ActiveSupport::Callbacks::Callback#start
0.00 4.93 0.00 37 0.00 0.00 Array#include?
0.00 4.93 0.00 316 0.00 0.00 File#basename
0.00 4.93 0.00 44 0.00 0.00 Regexp#===
0.00 4.93 0.00 22 0.00 0.00 Kernel.class
0.00 4.93 0.00 5 0.00 15.60 ActiveSupport::Callbacks::ClassMethods.__update_callbacks
0.00 4.93 0.00 5 0.00 0.00 ActiveSupport::Callbacks::Callback#initialize
0.00 4.93 0.00 5 0.00 6.40 ActiveSupport::Callbacks::CallbackChain#compile
0.00 4.93 0.00 1 0.00 0.00 Digest::Class#hexdigest
0.00 4.93 0.00 5 0.00 0.00 Kernel.with_warnings
0.00 4.93 0.00 6 0.00 0.00 Module#private
0.00 4.93 0.00 7 0.00 0.00 ActiveSupport::Dependencies.local_const_defined?
0.00 4.93 0.00 5 0.00 0.00 ActiveSupport::Dependencies.log_call
0.00 4.93 0.00 1 0.00 0.00 NameError#initialize
0.00 4.93 0.00 6 0.00 0.00 ActiveSupport::Callbacks::Callback#matches?
0.00 4.93 0.00 7 0.00 0.00 ActiveRecord::Base#_destroy_callbacks
0.00 4.93 0.00 3 0.00 0.00 ActiveRecord::Base#_validators
0.00 4.93 0.00 13 0.00 0.00 ActiveRecord::Base#_removed_validate_callbacks
0.00 4.93 0.00 6 0.00 0.00 ActiveSupport::Inflector.constantize
0.00 4.93 0.00 1 0.00 0.00 Enumerable.any?
0.00 4.93 0.00 56 0.00 0.00 Kernel.taint
0.00 4.93 0.00 6 0.00 0.00 Object#present?
0.00 4.93 0.00 14 0.00 4.43 Pathname#cleanpath
0.00 4.93 0.00 1 0.00 0.00 ActiveRecord::Validations::UniquenessValidator#setup
0.00 4.93 0.00 1 0.00 250.00 ActiveSupport::Dependencies.load_file
0.00 4.93 0.00 1 0.00 0.00 ActiveRecord::Validations::UniquenessValidator#initialize
0.00 4.93 0.00 110 0.00 0.00 Hash#[]
0.00 4.93 0.00 4 0.00 15.75 ActiveModel::Validations::ClassMethods.validate
0.00 4.93 0.00 11 0.00 1.45 ActiveSupport::Callbacks::Callback#end
0.00 4.93 0.00 1 0.00 0.00 ActiveSupport::Dependencies.load_once_paths
0.00 4.93 0.00 12 0.00 0.00 Fixnum#to_s
0.00 4.93 0.00 1 0.00 4930.00 Object#profile_me
0.00 4.93 0.00 1 0.00 0.00 Digest::Class#digest
0.00 4.93 0.00 4 0.00 0.00 Kernel.Array
0.00 4.93 0.00 3 0.00 0.00 ActiveSupport::Callbacks::Callback#name
0.00 4.93 0.00 262 0.00 0.00 Array#unshift
0.00 4.93 0.00 5 0.00 0.00 ActiveSupport::Callbacks::Callback#_compile_per_key_options
0.00 4.93 0.00 1 0.00 4524.00 User#encrypted_password
0.00 4.93 0.00 2 0.00 0.00 Digest::Base#reset
0.00 4.93 0.00 1 0.00 0.00 ActiveModel::Observing::ClassMethods.inherited
0.00 4.93 0.00 3 0.00 0.00 String#blank?
0.00 4.93 0.00 2 0.00 0.00 Module#attr_accessor
0.00 4.93 0.00 37 0.00 0.00 String#to_str
0.00 4.93 0.00 1 0.00 0.00 Exception#initialize
0.00 4.93 0.00 1 0.00 4930.00 #toplevel
edit app\models\user.rb
Environment
Thu, 25 Feb 2010 15:52:52 GMT
C:\ruby\bin\ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [i386-mingw32]
gem -v
1.3.6
bundle show
Gems included by the bundle:
* abstract (1.0.0)
* actionmailer (3.0.0.beta1)
* actionpack (3.0.0.beta1)
* activemodel (3.0.0.beta1)
* activerecord (3.0.0.beta1)
* activeresource (3.0.0.beta1)
* activesupport (3.0.0.beta1)
* arel (0.2.1)
* builder (2.1.2)
* bundler (0.9.8)
* erubis (2.6.5)
* i18n (0.3.3)
* mail (2.1.3)
* memcache-client (1.7.8)
* mime-types (1.16)
* rack (1.1.0)
* rack-mount (0.5.2)
* rack-test (0.5.3)
* rails (3.0.0.beta1)
* railties (3.0.0.beta1)
* rake (0.8.7)
* sqlite3-ruby (1.2.5)
* text-format (1.0.0)
* text-hyphen (1.0.0)
* thor (0.13.3)
* tzinfo (0.3.16)
rake about
(in C:/cygwin/home/rubys/git/awdwr/work/depot)
About your application's environment
Ruby version 1.8.7 (i386-mingw32)
RubyGems version 1.3.6
Rack version 1.1
Rails version 3.0.0.beta1
Active Record version 3.0.0.beta1
Action Pack version 3.0.0.beta1
Active Resource version 3.0.0.beta1
Action Mailer version 3.0.0.beta1
Active Support version 3.0.0.beta1
Middleware ActionDispatch::Static, Rack::Lock, Rack::Runtime, Rails::Rack::Logger, ActionDispatch::ShowExceptions, Rack::Sendfile, ActionDispatch::Callbacks, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, Rack::MethodOverride, ActionDispatch::Head
Application root C:/cygwin/home/rubys/git/awdwr/work/depot
Environment development
git log -1
commit df85ab41c1ff6992dd462a0e63dac9dcdcee0348
Author: José Valim <jose.valim@gmail.com>
Date: Wed Feb 24 22:06:24 2010 +0100
Renamed LocalizedCache to DetailsCache.
Todos