Agile Web Development with Rails, Edition 4

Agile Web Development with Rails, Edition 4

Table of Contents

2 Instant Gratification

We start with a simple "hello world!" demo application and in the process verify that everything is installed correctly.

Create the application

/home/rubys/git/rails/bin/rails new demo1
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/thor-0.14.0/lib/thor/util.rb:219: Use RbConfig instead of obsolete and deprecated Config.
      create  
      create  README
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
      create  app
      create  app/helpers/application_helper.rb
      create  app/views/layouts/application.html.erb
      create  app/controllers/application_controller.rb
      create  app/mailers
      create  app/models
      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/test.rb
      create  config/environments/production.rb
      create  config/initializers
      create  config/initializers/mime_types.rb
      create  config/initializers/inflections.rb
      create  config/initializers/session_store.rb
      create  config/initializers/backtrace_silencers.rb
      create  config/initializers/secret_token.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/500.html
      create  public/robots.txt
      create  public/favicon.ico
      create  public/422.html
      create  public/404.html
      create  public/index.html
      create  public/images
      create  public/images/rails.png
      create  public/stylesheets
      create  public/stylesheets/.gitkeep
      create  public/javascripts
      create  public/javascripts/prototype.js
      create  public/javascripts/dragdrop.js
      create  public/javascripts/rails.js
      create  public/javascripts/effects.js
      create  public/javascripts/controls.js
      create  public/javascripts/application.js
      create  script
      create  script/rails
      create  test
      create  test/performance/browsing_test.rb
      create  test/test_helper.rb
      create  test/fixtures
      create  test/unit
      create  test/functional
      create  test/integration
      create  tmp
      create  tmp/sessions
      create  tmp/sockets
      create  tmp/cache
      create  tmp/pids
      create  vendor/plugins
      create  vendor/plugins/.gitkeep
bundle install
Using rake (0.8.7) 
Using abstract (1.0.0) 
Using activesupport (3.1.0.beta) from source at /home/rubys/git/rails 
Using builder (2.1.2) 
Using i18n (0.4.1) 
Using activemodel (3.1.0.beta) from source at /home/rubys/git/rails 
Using erubis (2.6.6) 
Using rack (1.2.1) 
Using rack-mount (0.6.13) 
Using rack-test (0.5.4) 
Using tzinfo (0.3.23) 
Using actionpack (3.1.0.beta) from source at /home/rubys/git/rails 
Using mime-types (1.16) 
Using polyglot (0.3.1) 
Using treetop (1.4.8) 
Using mail (2.2.5) 
Using actionmailer (3.1.0.beta) from source at /home/rubys/git/rails 
Using arel (1.0.1) from source at /home/rubys/git/arel 
Using activerecord (3.1.0.beta) from source at /home/rubys/git/rails 
Using activeresource (3.1.0.beta) from source at /home/rubys/git/rails 
Using bundler (1.0.0) 
Using thor (0.14.0) 
Using railties (3.1.0.beta) from source at /home/rubys/git/rails 
Using rails (3.1.0.beta) from source at /home/rubys/git/rails 
Using sqlite3-ruby (1.3.1) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
*[32m
Your bundle was installed to `/home/rubys/.rvm/gems/ruby-1.9.3-r29181`*[0m

See what files were created

ls -p
app/	 config.ru  doc/     Gemfile.lock  log/     Rakefile  script/  tmp/
config/  db/	    Gemfile  lib/	   public/  README    test/    vendor/

Create a simple controller

rails generate controller Say hello goodbye
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      create  app/controllers/say_controller.rb
       route  get "say/goodbye"
       route  get "say/hello"
      invoke  erb
      create    app/views/say
      create    app/views/say/hello.html.erb
      create    app/views/say/goodbye.html.erb
      invoke  test_unit
      create    test/functional/say_controller_test.rb
      invoke  helper
      create    app/helpers/say_helper.rb
      invoke    test_unit
      create      test/unit/helpers/say_helper_test.rb
edit app/controllers/say_controller.rb
class SayController < ApplicationController
  def hello
  end
 
  def goodbye
  end
 
end

Start the server.

Attempt to fetch the file - note that it is missing

get /say/hello

Say#hello

Find me in app/views/say/hello.html.erb

Replace file with a simple hello world

edit app/views/say/hello.html.erb
<h1>Hello from Rails!</h1>

This time it works!

get /say/hello

Hello from Rails!

pub work/demo1

Add a simple expression

edit app/views/say/hello.html.erb
<h1>Hello from Rails!</h1>
<p>
  It is now <%= Time.now %>
</p>
get /say/hello

Hello from Rails!

It is now 2010-09-06 10:39:25 -0400

pub work/demo2

Evaluate the expression in the controller.

edit app/controllers/say_controller.rb
class SayController < ApplicationController
  def hello
    @time = Time.now
  end
 
  def goodbye
  end
 
end

Reference the result in the view.

edit app/views/say/hello.html.erb
<h1>Hello from Rails!</h1>
<p>
  It is now <%= @time %>
</p>
get /say/hello

Hello from Rails!

It is now 2010-09-06 10:39:26 -0400

pub work/demo3

Replace the goodbye template

edit app/views/say/goodbye.html.erb
<h1>Goodbye!</h1>
<p>
  It was nice having you here.
</p>
get /say/goodbye

Goodbye!

It was nice having you here.

pub work/demo4

Add a link from the hello page to the goodbye page

edit app/views/say/hello.html.erb
<h1>Hello from Rails!</h1>
<p>
  It is now <%= @time %>
</p>
<p>
  Time to say
  <%= link_to "Goodbye!", say_goodbye_path %>
</p>
get /say/hello

Hello from Rails!

It is now 2010-09-06 10:39:27 -0400

Time to say Goodbye!

Add a link back to the hello page

edit app/views/say/goodbye.html.erb
<h1>Goodbye!</h1>
<p>
  It was nice having you here.
</p>
<p>
  Say <%= link_to "Hello", say_hello_path %> again.
</p>
get /say/goodbye

Goodbye!

It was nice having you here.

Say Hello again.

pub work/demo5

6.1 Iteration A1: Creating the Products Maintenance Application

Expected exactly 0 elements matching ".stderr", found 43.

Traceback:
  /home/rubys/svn/rails4/Book/util/checkdepot.rb:30:in `block in <class:DepotTest>'

This section mostly covers database configuration options for those users that insist on using MySQL. SQLite3 users will skip most of it.

Create the application.

/home/rubys/git/rails/bin/rails new depot
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/thor-0.14.0/lib/thor/util.rb:219: Use RbConfig instead of obsolete and deprecated Config.
      create  
      create  README
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
      create  app
      create  app/helpers/application_helper.rb
      create  app/views/layouts/application.html.erb
      create  app/controllers/application_controller.rb
      create  app/mailers
      create  app/models
      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/test.rb
      create  config/environments/production.rb
      create  config/initializers
      create  config/initializers/mime_types.rb
      create  config/initializers/inflections.rb
      create  config/initializers/session_store.rb
      create  config/initializers/backtrace_silencers.rb
      create  config/initializers/secret_token.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/500.html
      create  public/robots.txt
      create  public/favicon.ico
      create  public/422.html
      create  public/404.html
      create  public/index.html
      create  public/images
      create  public/images/rails.png
      create  public/stylesheets
      create  public/stylesheets/.gitkeep
      create  public/javascripts
      create  public/javascripts/prototype.js
      create  public/javascripts/dragdrop.js
      create  public/javascripts/rails.js
      create  public/javascripts/effects.js
      create  public/javascripts/controls.js
      create  public/javascripts/application.js
      create  script
      create  script/rails
      create  test
      create  test/performance/browsing_test.rb
      create  test/test_helper.rb
      create  test/fixtures
      create  test/unit
      create  test/functional
      create  test/integration
      create  tmp
      create  tmp/sessions
      create  tmp/sockets
      create  tmp/cache
      create  tmp/pids
      create  vendor/plugins
      create  vendor/plugins/.gitkeep
bundle install
Using rake (0.8.7) 
Using abstract (1.0.0) 
Using activesupport (3.1.0.beta) from source at /home/rubys/git/rails 
Using builder (2.1.2) 
Using i18n (0.4.1) 
Using activemodel (3.1.0.beta) from source at /home/rubys/git/rails 
Using erubis (2.6.6) 
Using rack (1.2.1) 
Using rack-mount (0.6.13) 
Using rack-test (0.5.4) 
Using tzinfo (0.3.23) 
Using actionpack (3.1.0.beta) from source at /home/rubys/git/rails 
Using mime-types (1.16) 
Using polyglot (0.3.1) 
Using treetop (1.4.8) 
Using mail (2.2.5) 
Using actionmailer (3.1.0.beta) from source at /home/rubys/git/rails 
Using arel (1.0.1) from source at /home/rubys/git/arel 
Using activerecord (3.1.0.beta) from source at /home/rubys/git/rails 
Using activeresource (3.1.0.beta) from source at /home/rubys/git/rails 
Using bundler (1.0.0) 
Using thor (0.14.0) 
Using railties (3.1.0.beta) from source at /home/rubys/git/rails 
Using rails (3.1.0.beta) from source at /home/rubys/git/rails 
Using sqlite3-ruby (1.3.1) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
*[32m
Your bundle was installed to `/home/rubys/.rvm/gems/ruby-1.9.3-r29181`*[0m

Look at the files created.

ls -p
app/	 config.ru  doc/     Gemfile.lock  log/     Rakefile  script/  tmp/
config/  db/	    Gemfile  lib/	   public/  README    test/    vendor/

Database configuration options (generally not required for sqlite3)

cat config/database.yml
# SQLite version 3.x
#   gem install sqlite3-ruby (not necessary on OS X Leopard)
development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000
 
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: sqlite3
  database: db/test.sqlite3
  pool: 5
  timeout: 5000
 
production:
  adapter: sqlite3
  database: db/production.sqlite3
  pool: 5
  timeout: 5000

Generate scaffolding for a real model, modify a template, and do our first bit of data entry.

Generating our first model and associated scaffolding

rails generate scaffold Product title:string description:text image_url:string price:decimal
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      invoke  active_record
      create    db/migrate/20100906143933_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
      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

Break lines for formatting reasons

edit app/controllers/products_controller.rb
class ProductsController < ApplicationController
  # GET /products
  # GET /products.xml
  def index
    @products = Product.all
 
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @products }
    end
  end
 
  # GET /products/1
  # GET /products/1.xml
  def show
    @product = Product.find(params[:id])
 
    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @product }
    end
  end
 
  # GET /products/new
  # GET /products/new.xml
  def new
    @product = Product.new
 
    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @product }
    end
  end
 
  # GET /products/1/edit
  def edit
    @product = Product.find(params[:id])
  end
 
  # POST /products
  # POST /products.xml
  def create
    @product = Product.new(params[:product])
 
    respond_to do |format|
      if @product.save
        format.html { redirect_to(@product,
          :notice => 'Product was successfully created.') }
        format.xml  { render :xml => @product, :status => :created,
          :location => @product }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @product.errors,
          :status => :unprocessable_entity }
      end
    end
  end
 
  # PUT /products/1
  # PUT /products/1.xml
  def update
    @product = Product.find(params[:id])
 
    respond_to do |format|
      if @product.update_attributes(params[:product])
        format.html { redirect_to(@product,
          :notice => 'Product was successfully updated.') }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @product.errors,
          :status => :unprocessable_entity }
      end
    end
  end
 
  # DELETE /products/1
  # DELETE /products/1.xml
  def destroy
    @product = Product.find(params[:id])
    @product.destroy
 
    respond_to do |format|
      format.html { redirect_to(products_url) }
      format.xml  { head :ok }
    end
  end
end
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 %>

Restart the server.

Add precision and scale to the price

edit db/migrate/20100906143933_create_products.rb
class CreateProducts < ActiveRecord::Migration
  def self.up
    create_table :products do |t|
      t.string :title
      t.text :description
      t.string :image_url
      t.decimal :price, :precision => 8, :scale => 2
 
      t.timestamps
    end
  end
 
  def self.down
    drop_table :products
  end
end

Apply the migration

rake db:migrate
mv 20100906143933_create_products.rb 20100301000001_create_products.rb
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
==  CreateProducts: migrating =================================================
-- create_table(:products)
   -> 0.0019s
==  CreateProducts: migrated (0.0020s) ========================================
 

Get an (empty) list of products

get /products

Listing products

Title Description Image url Price

New Product

Show (and modify) one of the templates produced

edit app/views/products/_form.html.erb
<%= form_for(@product) do |f| %>
  <% if @product.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@product.errors.count, "error") %>
      prohibited this product from being saved:</h2>
 
      <ul>
      <% @product.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
 
  <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 %>

Create a product

get /products/new

New product





Back
post /products
You are being redirected.
get http://localhost:3000/products/1

Product was successfully created.

Title: Web Design for Developers

Description: <p> <em>Web Design for Developers</em> will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation. </p>

Image url: /images/wd4d.jpg

Price: 42.95

Edit | Back

Verify that the product has been added

get /products

Listing products

Title Description Image url Price
Web Design for Developers <p> <em>Web Design for Developers</em> will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation. </p> /images/wd4d.jpg 42.95 Show Edit Destroy

New Product

And, just to verify that we haven't broken anything

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_the_truth is already defined in ProductTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/product_test.rb:5:in `<class:ProductTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/product_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:8:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!
pub depot_a

6.2 Iteration A2: Making Prettier Listings

Show the relationship between various artifacts: seed data, stylesheets, html, and images.

Load some "seed" data

edit db/seeds.rb
Product.delete_all
 
Product.create(:title => 'Programming Ruby 1.9',
  :description =>
      %{<p>
        Ruby is the fastest growing and most exciting dynamic language out
        there. If you need to get working programs delivered fast, you should
        add Ruby to your toolbox.
      </p>},
  :image_url => '/images/ruby.jpg',
  :price => 49.50)
  # . . .
rake db:seed
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)

Link to the stylesheet in the layout

edit app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
  <title>Depot</title>
  <%= stylesheet_link_tag :all %>
  <%= javascript_include_tag :defaults %>
  <%= csrf_meta_tag %>
</head>

Replace the scaffold generated view with some custom HTML

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><%= product.title %></dt>
          <dd><%= truncate(strip_tags(product.description),
                 :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 %>

Copy some images and a stylesheet

cp -v /home/rubys/svn/rails4/Book/util/data/images/* public/images/
`/home/rubys/svn/rails4/Book/util/data/images/debug.jpg' -> `public/images/debug.jpg'
`/home/rubys/svn/rails4/Book/util/data/images/logo.png' -> `public/images/logo.png'
`/home/rubys/svn/rails4/Book/util/data/images/rails.png' -> `public/images/rails.png'
`/home/rubys/svn/rails4/Book/util/data/images/rtp.jpg' -> `public/images/rtp.jpg'
`/home/rubys/svn/rails4/Book/util/data/images/ruby.jpg' -> `public/images/ruby.jpg'
`/home/rubys/svn/rails4/Book/util/data/images/wd4d.jpg' -> `public/images/wd4d.jpg'
cp -v /home/rubys/svn/rails4/Book/util/data/depot.css public/stylesheets
`/home/rubys/svn/rails4/Book/util/data/depot.css' -> `public/stylesheets/depot.css'

See the finished result

get /products

Listing products

Wd4d
Web Design for Developers
Web Design for Developers will show you how to make your web-b...
Show
Edit
Destroy
Ruby
Programming Ruby 1.9
Ruby is the fastest growing and most exciting dynamic language out ...
Show
Edit
Destroy
Debug
Debug It!
Professional programmers develop a knack of unerringly zeroing in on...
Show
Edit
Destroy

New product

6.3 Playtime

Configuration management using Git.

Configure Git.

git repo-config --get-regexp user.*
user.name Sam Ruby
user.email rubys@intertwingly.net

Look at the .gitignore that Rails helpfully provided...

cat .gitignore
.bundle
db/*.sqlite3
log/*.log
tmp/**/*

Initialize repository.

git init
Initialized empty Git repository in .git/

Add all the files.

git add .

Initial commit.

git commit -m "Depot Scaffold"
Created initial commit c76e6d1: Depot Scaffold
 61 files changed, 10818 insertions(+), 0 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 Gemfile
 create mode 100644 Gemfile.lock
 create mode 100644 README
 create mode 100644 Rakefile
 create mode 100644 app/controllers/application_controller.rb
 create mode 100644 app/controllers/products_controller.rb
 create mode 100644 app/helpers/application_helper.rb
 create mode 100644 app/helpers/products_helper.rb
 create mode 100644 app/models/product.rb
 create mode 100644 app/views/layouts/application.html.erb
 create mode 100644 app/views/products/_form.html.erb
 create mode 100644 app/views/products/edit.html.erb
 create mode 100644 app/views/products/index.html.erb
 create mode 100644 app/views/products/new.html.erb
 create mode 100644 app/views/products/show.html.erb
 create mode 100644 config.ru
 create mode 100644 config/application.rb
 create mode 100644 config/boot.rb
 create mode 100644 config/database.yml
 create mode 100644 config/environment.rb
 create mode 100644 config/environments/development.rb
 create mode 100644 config/environments/production.rb
 create mode 100644 config/environments/test.rb
 create mode 100644 config/initializers/backtrace_silencers.rb
 create mode 100644 config/initializers/inflections.rb
 create mode 100644 config/initializers/mime_types.rb
 create mode 100644 config/initializers/secret_token.rb
 create mode 100644 config/initializers/session_store.rb
 create mode 100644 config/locales/en.yml
 create mode 100644 config/routes.rb
 create mode 100644 db/migrate/20100301000001_create_products.rb
 create mode 100644 db/schema.rb
 create mode 100644 db/seeds.rb
 create mode 100644 doc/README_FOR_APP
 create mode 100644 lib/tasks/.gitkeep
 create mode 100644 public/404.html
 create mode 100644 public/422.html
 create mode 100644 public/500.html
 create mode 100644 public/favicon.ico
 create mode 100644 public/images/debug.jpg
 create mode 100644 public/images/logo.png
 create mode 100644 public/images/rails.png
 create mode 100644 public/images/rtp.jpg
 create mode 100644 public/images/ruby.jpg
 create mode 100644 public/images/wd4d.jpg
 create mode 100644 public/index.html
 create mode 100644 public/javascripts/application.js
 create mode 100644 public/javascripts/controls.js
 create mode 100644 public/javascripts/dragdrop.js
 create mode 100644 public/javascripts/effects.js
 create mode 100644 public/javascripts/prototype.js
 create mode 100644 public/javascripts/rails.js
 create mode 100644 public/robots.txt
 create mode 100644 public/stylesheets/.gitkeep
 create mode 100644 public/stylesheets/depot.css
 create mode 100644 public/stylesheets/scaffold.css
 create mode 100755 script/rails
 create mode 100644 test/fixtures/products.yml
 create mode 100644 test/functional/products_controller_test.rb
 create mode 100644 test/performance/browsing_test.rb
 create mode 100644 test/test_helper.rb
 create mode 100644 test/unit/helpers/products_helper_test.rb
 create mode 100644 test/unit/product_test.rb
 create mode 100644 vendor/plugins/.gitkeep

7.1 Iteration B1: Validate!

Augment the model with a few vailidity checks.

Various validations: required, numeric, positive, and unique

edit app/models/product.rb
class Product < ActiveRecord::Base
  validates :title, :description, :image_url, :presence => true
  validates :price, :numericality => {:greater_than_or_equal_to => 0.01}
  validates :title, :uniqueness => true
  validates :image_url, :allow_blank => true, :format => {
    :with    => %r{\.(gif|jpg|png)$}i,
    :message => 'must be a URL for GIF, JPG or PNG image.'
  }
end

Demonstrate failures.

get /products/new

New product





Back
post /products

New product

4 errors prohibited this product from being saved:

  • Title can't be blank
  • Description can't be blank
  • Image url can't be blank
  • Price must be greater than or equal to 0.01




Back

Demonstrate more failures.

get /products/new

New product





Back
post /products

New product

1 error prohibited this product from being saved:

  • Price is not a number




Back
edit app/models/product.rb
class Product < ActiveRecord::Base
  validates :title, :description, :image_url, :presence => true
  validates :price, :numericality => {:greater_than_or_equal_to => 0.01}
  validates :title, :uniqueness => true
  validates :image_url, :format => {
    :with    => %r{\.(gif|jpg|png)$}i,
    :message => 'must be a URL for GIF, JPG or PNG image.'
  }
end
pub depot_b

7.2 Iteration B2: Unit Testing

</1 tests, 1 assertions, 0 failures, 0 errors/> expected but was
<"helpers">.

Traceback:
  /home/rubys/svn/rails4/Book/util/checkdepot.rb:66:in `block in <class:DepotTest>'

Introduce the importance of unit testing.

Look at what files are generated

ls test/unit
helpers
product_test.rb

Add a fixture.

edit test/fixtures/products.yml
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
 
one:
  title: MyString
  description: MyText
  image_url: MyString
  price: 9.99
 
two:
  title: MyString
  description: MyText
  image_url: MyString
  price: 9.99
 
ruby: 
  title:       Programming Ruby 1.9
  description: 
    Ruby is the fastest growing and most exciting dynamic
    language out there.  If you need to get working programs
    delivered fast, you should add Ruby to your toolbox.
  price:       49.50
  image_url:   ruby.png 

Now run the tests... and watch them fail :-(

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_the_truth is already defined in ProductTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/product_test.rb:5:in `<class:ProductTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/product_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:8:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!

Solution is simple, provide valid data.

edit test/functional/products_controller_test.rb
require 'test_helper'
 
class ProductsControllerTest < ActionController::TestCase
  # ...
  setup do
    @product = products(:one)
    @update = {
      :title       => 'Lorem Ipsum',
      :description => 'Wibbles are fun!',
      :image_url   => 'lorem.jpg',
      :price       => 19.95
    }
  end
 
  test "should get index" do
    get :index
    assert_response :success
    assert_not_nil assigns(:products)
  end
 
  test "should get new" do
    get :new
    assert_response :success
  end
 
  test "should create product" do
    assert_difference('Product.count') do
      post :create, :product => @update
    end
 
    assert_redirected_to product_path(assigns(:product))
  end
 
  # ...
  test "should update product" do
    put :update, :id => @product.to_param, :product => @update
    assert_redirected_to product_path(assigns(:product))
  end
 
  # ...
end

Tests now pass again :-)

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_the_truth is already defined in ProductTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/product_test.rb:5:in `<class:ProductTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/product_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:20:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!

Add some unit tests for new function.

edit test/unit/product_test.rb
require 'test_helper'
 
class ProductTest < ActiveSupport::TestCase
  test "product attributes must not be empty" do
    product = Product.new
    assert product.invalid?
    assert product.errors[:title].any?
    assert product.errors[:description].any?
    assert product.errors[:price].any?
    assert product.errors[:image_url].any?
  end
 
  test "product price must be positive" do
    product = Product.new(:title       => "My Book Title",
                          :description => "yyy",
                          :image_url   => "zzz.jpg")
    product.price = -1
    assert product.invalid?
    assert_equal "must be greater than or equal to 0.01", 
      product.errors[:price].join('; ')
 
    product.price = 0
    assert product.invalid?
    assert_equal "must be greater than or equal to 0.01", 
      product.errors[:price].join('; ')
 
    product.price = 1
    assert product.valid?
  end
 
  def new_product(image_url)
    Product.new(:title       => "My Book Title",
                :description => "yyy",
                :price       => 1,
                :image_url   => image_url)
  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|
      assert new_product(name).valid?, "#{name} shouldn't be invalid"
    end
 
    bad.each do |name|
      assert new_product(name).invalid?, "#{name} shouldn't be valid"
    end
  end
 
  test "product is not valid without a unique title" do
    product = Product.new(:title       => products(:ruby).title,
                          :description => "yyy", 
                          :price       => 1, 
                          :image_url   => "fred.gif")
 
    assert !product.save
    assert_equal "has already been taken", product.errors[:title].join('; ')
  end
 
  test "product is not valid without a unique title - i18n" do
    product = Product.new(:title       => products(:ruby).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

Tests pass!

rake test:units
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_product_attributes_must_not_be_empty is already defined in ProductTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/product_test.rb:5:in `<class:ProductTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/product_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
rake aborted!
Command failed with status (1): [/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/...]

    
(See full trace by running task with --trace)

7.3 Playtime

Save our work

Show what files we changed.

git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#	modified:   app/models/product.rb
#	modified:   test/fixtures/products.yml
#	modified:   test/functional/products_controller_test.rb
#	modified:   test/unit/product_test.rb
#
no changes added to commit (use "git add" and/or "git commit -a")

Commit changes using -a shortcut

git commit -a -m 'Validation!'
Created commit 9550536: Validation!
 4 files changed, 135 insertions(+), 5 deletions(-)
pub depot_c
edit app/models/product.rb
class Product < ActiveRecord::Base
  validates :title, :description, :image_url, :presence => true
  validates :price, :numericality => {:greater_than_or_equal_to => 0.01}
  validates :title, :uniqueness => true
  validates :image_url, :format => {
    :with    => %r{\.(gif|jpg|png)$}i,
    :message => 'must be a URL for GIF, JPG or PNG image.'
  }
  validates :title, :length => {:minimum => 10}
end

8.1 Iteration C1: Create the Catalog Listing

Show the model, view, and controller working together.

Create a second controller with a single index action

rails generate controller store index
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      create  app/controllers/store_controller.rb
       route  get "store/index"
      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

Route the 'root' of the site to the store

edit config/routes.rb
Depot::Application.routes.draw do
  get "store/index"
 
  resources :products
 
  # ...
 
  # You can have the root of your site routed with "root"
  # just remember to delete public/index.html.
  # root :to => "welcome#index"
  root :to => 'store#index', :as => 'store'
 
  # ...
end

Delete public/index.html, as instructed.

rm public/index.html

Demonstrate that everything is wired together

get /

Store#index

Find me in app/views/store/index.html.erb

In the controller, get a list of products from the model

edit app/controllers/store_controller.rb
class StoreController < ApplicationController
  def index
    @products = Product.all
  end
 
end

In the model, define a default sort order

edit app/models/product.rb
class Product < ActiveRecord::Base
  default_scope :order => 'title'
 
  # validation stuff...
end

In the view, display a list of products

edit app/views/store/index.html.erb
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
 
<h1>Your Pragmatic Catalog</h1>
 
<% @products.each do |product| %>
  <div class="entry">
    <%= image_tag(product.image_url) %>
    <h3><%= product.title %></h3>
    <%=sanitize product.description %>
    <div class="price_line">
      <span class="price"><%= product.price %></span>
    </div>
  </div>
<% end %>

Show our first (ugly) catalog page

get /

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

49.5
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

42.95
pub depot_d

8.2 Iteration C2: Add a Page Layout

Demonstrate layouts.

Modify the application layout

edit app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
  <title>Pragprog Books Online Store</title>
  <%= stylesheet_link_tag "scaffold" %>
  <%= stylesheet_link_tag "depot", :media => "all" %><!-- <label id="code.slt"/> -->
  <%= javascript_include_tag :defaults %>
  <%= csrf_meta_tag %><!-- <label id="code.csrf"/> -->
</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 %><!-- <label id="code.depot.e.include"/> -->
    </div>
  </div>
</body>
</html>

Modify the stylesheet

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;
}

Show the results.

get /

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

49.5
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

42.95

8.3 Iteration C3: Use a Helper to Format the Price

Demonstrate helpers.

Format the price using a built-in helper.

edit app/views/store/index.html.erb
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
 
<h1>Your Pragmatic Catalog</h1>
 
<% @products.each do |product| %>
  <div class="entry">
    <%= image_tag(product.image_url) %>
    <h3><%= product.title %></h3>
    <%=sanitize product.description %>
    <div class="price_line">
      <span class="price"><%= number_to_currency(product.price) %></span>
    </div>
  </div>
<% end %>

Show the results.

get /

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95

8.4 Iteration C4: Functional Testing

</5 tests, 23 assertions, 0 failures, 0 errors/> expected but was
<"(in /home/rubys/svn/rails4/Book/util/work-193/depot)">.

Traceback:
  /home/rubys/svn/rails4/Book/util/checkdepot.rb:86:in `block in <class:DepotTest>'

Demonstrate use of assert_select to test views.

Verify that the tests still pass.

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_product_attributes_must_not_be_empty is already defined in ProductTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/product_test.rb:5:in `<class:ProductTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/product_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:20:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!

Add tests for layout, product display, and formatting, using counts, string comparisons, and regular expressions.

edit test/functional/store_controller_test.rb
require 'test_helper'
 
class StoreControllerTest < ActionController::TestCase
  test "should get index" do
    get :index
    assert_response :success
    assert_select '#columns #side a', :minimum => 4
    assert_select '#main .entry', 3
    assert_select 'h3', 'Programming Ruby 1.9'
    assert_select '.price', /\$[,\d]+\.\d\d/
  end
 
end

Show that the tests pass.

rake test:functionals
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:20:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
rake aborted!
Command failed with status (1): [/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/...]

    
(See full trace by running task with --trace)
pub depot_e

8.5 Playtime

git tag iteration-b
git commit -a -m "Prettier listings"
Created commit b0effcd: Prettier listings
 5 files changed, 98 insertions(+), 257 deletions(-)
 rewrite app/views/layouts/application.html.erb (66%)
 delete mode 100644 public/index.html
git tag iteration-c

9.1 Iteration D1: Finding a Cart

Create a cart. Put it in a session. Find it.

Create a cart.

rails generate scaffold Cart
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      invoke  active_record
      create    db/migrate/20100906144054_create_carts.rb
      create    app/models/cart.rb
      invoke    test_unit
      create      test/unit/cart_test.rb
      create      test/fixtures/carts.yml
       route  resources :carts
      invoke  scaffold_controller
      create    app/controllers/carts_controller.rb
      invoke    erb
      create      app/views/carts
      create      app/views/carts/index.html.erb
      create      app/views/carts/edit.html.erb
      create      app/views/carts/show.html.erb
      create      app/views/carts/new.html.erb
      create      app/views/carts/_form.html.erb
      invoke    test_unit
      create      test/functional/carts_controller_test.rb
      invoke    helper
      create      app/helpers/carts_helper.rb
      invoke      test_unit
      create        test/unit/helpers/carts_helper_test.rb
      invoke  stylesheets
   identical    public/stylesheets/scaffold.css
rake db:migrate
mv 20100906144054_create_carts.rb 20100301000002_create_carts.rb
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
==  CreateCarts: migrating ====================================================
-- create_table(:carts)
   -> 0.0016s
==  CreateCarts: migrated (0.0017s) ===========================================
 

Implement current_cart, which creates a new cart if it can't find one.

edit app/controllers/application_controller.rb

Replace with signed cookies?

class ApplicationController < ActionController::Base
  protect_from_forgery
 
  private
 
    def current_cart 
      Cart.find(session[:cart_id])
    rescue ActiveRecord::RecordNotFound
      cart = Cart.create
      session[:cart_id] = cart.id
      cart
    end
end

9.2 Iteration D2: Connecting Products to Carts

Create line item which connects products to carts'

Create the model object.

rails generate scaffold LineItem product_id:integer cart_id:integer
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      invoke  active_record
      create    db/migrate/20100906144101_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
      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
rake db:migrate
mv 20100906144101_create_line_items.rb 20100301000003_create_line_items.rb
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
==  CreateLineItems: migrating ================================================
-- create_table(:line_items)
   -> 0.0019s
==  CreateLineItems: migrated (0.0019s) =======================================
 

Cart has many line items.

edit app/models/cart.rb
class Cart < ActiveRecord::Base
  has_many :line_items, :dependent => :destroy
end

Product has many line items.

edit app/models/product.rb
class Product < ActiveRecord::Base
  default_scope :order => 'title'
  has_many :line_items
 
  before_destroy :ensure_not_referenced_by_any_line_item
 
  # ensure that there are no line items referencing this product
  def ensure_not_referenced_by_any_line_item
    if line_items.count.zero?
      return true
    else
      errors[:base] << "Line Items present"
      return false
    end
  end
 
  #...

Line item belongs to both Cart and Product (But slightly more to the Cart). Also provide convenient access to the total price of the line item

edit app/models/line_item.rb
class LineItem < ActiveRecord::Base
  belongs_to :product
  belongs_to :cart
end

9.3 Iteration D3: Adding a button

Now we connect the model objects we created to the controller and the view.

Add the button, connecting it to the Line Item Controller, passing the product id.

edit app/views/store/index.html.erb
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
 
<h1>Your Pragmatic Catalog</h1>
 
<% @products.each do |product| %>
  <div class="entry">
    <%= image_tag(product.image_url) %>
    <h3><%= product.title %></h3>
    <%=sanitize product.description %>
    <div class="price_line">
      <span class="price"><%= number_to_currency(product.price) %></span>
      <%= button_to 'Add to Cart', line_items_path(:product_id => product) %>
    </div>
  </div>
<% end %>

Add a bit of style to make it show all on one line

edit public/stylesheets/depot.css
#store .entry form, #store .entry form div {
  display: inline;
}

Update the LineItem.new call to use current_cart and the product id. Additionally change the logic so that redirection upon success goes to the cart instead of the line item.

edit app/controllers/line_items_controller.rb
  def create
    @cart = current_cart
    product = Product.find(params[:product_id])
    @line_item = @cart.line_items.build(:product => product)
 
    respond_to do |format|
      if @line_item.save
        format.html { redirect_to(@line_item.cart,
          :notice => 'Line item was successfully created.') }
        format.xml  { render :xml => @line_item,
          :status => :created, :location => @line_item }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @line_item.errors,
          :status => :unprocessable_entity }
      end
    end
  end

Try it once, and see that the output isn't very useful yet.

get /

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
post /line_items?product_id=3
You are being redirected.
get http://localhost:3000/carts/1

Line item was successfully created.

Edit | Back

Update the template that shows the Cart.

edit app/views/carts/show.html.erb
<h2>Your Pragmatic Cart</h2>
<ul>    
  <% for item in @cart.line_items %>
    <li><%= item.product.title %></li>
  <% end %>
</ul>

Try it once again, and see that the products in the cart.

get /

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
post /line_items?product_id=3
You are being redirected.
get http://localhost:3000/carts/1

Your Pragmatic Cart

  • Programming Ruby 1.9
  • Programming Ruby 1.9
pub depot_f

9.4 Playtime

</7 tests, 25 assertions, 0 failures, 0 errors/> expected but was
<"(in /home/rubys/svn/rails4/Book/util/work-193/depot)">.

Traceback:
  /home/rubys/svn/rails4/Book/util/checkdepot.rb:99:in `block in <class:DepotTest>'

Once again, get the tests working, and add tests for the smarter cart.

See that the tests fail.

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_the_truth is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:5:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:20:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!

Update parameters passed as well as expected target of redirect

edit test/functional/line_items_controller_test.rb
  test "should create line_item" do
    assert_difference('LineItem.count') do
      post :create, :product_id => products(:ruby).id
    end
 
    assert_redirected_to cart_path(assigns(:line_item).cart)
  end
rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_the_truth is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:5:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:20:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!

10.1 Iteration E1: Creating a Smarter Cart

Change the cart to track the quantity of each product.

Add a quantity column to the line_item table in the database.

rails generate migration add_quantity_to_line_item quantity:integer
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      invoke  active_record
      create    db/migrate/20100906144134_add_quantity_to_line_item.rb

Modify the migration to add a default value for the new column

edit db/migrate/20100906144134_add_quantity_to_line_item.rb
class AddQuantityToLineItem < ActiveRecord::Migration
  def self.up
    add_column :line_items, :quantity, :integer, :default => 1
  end
 
  def self.down
    remove_column :line_items, :quantity
  end
end

Apply the migration

rake db:migrate
mv 20100906144134_add_quantity_to_line_item.rb 20100301000004_add_quantity_to_line_item.rb
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
==  AddQuantityToLineItem: migrating ==========================================
-- add_column(:line_items, :quantity, :integer, {:default=>1})
   -> 0.0107s
==  AddQuantityToLineItem: migrated (0.0108s) =================================
 

Create a method to add a product to the cart by either incrementing the quantity of an existing line item, or creating a new line item.

edit app/models/cart.rb
  def add_product(product_id)
    current_item = line_items.where(:product_id => product_id).first
    if current_item
      current_item.quantity += 1
    else
      current_item = LineItem.new(:product_id=>product_id)
      line_items << current_item
    end
    current_item
  end

Replace the call to LineItem.new with a call to the new method.

edit app/controllers/line_items_controller.rb
  def create
    @cart = current_cart
    product = Product.find(params[:product_id])
    @line_item = @cart.add_product(product.id)
 
    respond_to do |format|
      if @line_item.save
        format.html { redirect_to(@line_item.cart,
          :notice => 'Line item was successfully created.') }
        format.xml  { render :xml => @line_item,
          :status => :created, :location => @line_item }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @line_item.errors,
          :status => :unprocessable_entity }
      end
    end
  end

Update the view to show both columns.

edit app/views/carts/show.html.erb
<h2>Your Pragmatic Cart</h2>
<ul>    
  <% for item in @cart.line_items %>
    <li><%= item.quantity %> &times; <%= item.product.title %></li>
  <% end %>
</ul>

Look at the cart, and see that's not exactly what we intended

get /carts/1

Your Pragmatic Cart

  • 1 × Programming Ruby 1.9
  • 1 × Programming Ruby 1.9

Generate a migration to combine/separate items in carts.

rails generate migration combine_items_in_cart
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      invoke  active_record
      create    db/migrate/20100906144140_combine_items_in_cart.rb

Fill in the self.up method

edit db/migrate/20100906144140_combine_items_in_cart.rb
  def self.up
    # replace multiple items for a single product in a cart with a single item
    Cart.all.each do |cart|
      # count the number of each product in the cart
      sums = cart.line_items.group(:product_id).sum(:quantity)
 
      sums.each do |product_id, quantity|
        if quantity > 1
          # remove individual items
          cart.line_items.where(:product_id=>product_id).delete_all
 
          # replace with a single item
          cart.line_items.create(:product_id=>product_id, :quantity=>quantity)
        end
      end
    end
  end

Combine entries

rake db:migrate
mv 20100906144140_combine_items_in_cart.rb 20100301000005_combine_items_in_cart.rb
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
==  CombineItemsInCart: migrating =============================================
==  CombineItemsInCart: migrated (0.1791s) ====================================
 

Verify that the entries have been combined.

get /carts/1

Your Pragmatic Cart

  • 2 × Programming Ruby 1.9

Fill in the self.down method

edit db/migrate/20100301000005_combine_items_in_cart.rb
  def self.down
    # split items with quantity>1 into multiple items
    LineItem.where("quantity>1").each do |lineitem|
      # add individual items
      lineitem.quantity.times do 
        LineItem.create :cart_id=>lineitem.cart_id,
          :product_id=>lineitem.product_id, :quantity=>1
      end
 
      # remove original item
      lineitem.destroy
    end
  end

Separate out individual items.

rake db:rollback
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
==  CombineItemsInCart: reverting =============================================
==  CombineItemsInCart: reverted (0.1129s) ====================================
 

Every item should (once again) only have a quantity of one.

get /carts/1

Your Pragmatic Cart

  • 1 × Programming Ruby 1.9
  • 1 × Programming Ruby 1.9

Recombine the item data.

rake db:migrate
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
==  CombineItemsInCart: migrating =============================================
==  CombineItemsInCart: migrated (0.1759s) ====================================
 

Add a few products to the order.

post /line_items?product_id=2
You are being redirected.
get http://localhost:3000/carts/1

Your Pragmatic Cart

  • 2 × Programming Ruby 1.9
  • 1 × Web Design for Developers
post /line_items?product_id=3
You are being redirected.
get http://localhost:3000/carts/1

Your Pragmatic Cart

  • 3 × Programming Ruby 1.9
  • 1 × Web Design for Developers
pub depot_g

Try something malicious.

get /carts/wibble

ActiveRecord::RecordNotFound in CartsController#show

Couldn't find Cart with ID=wibble

Rails.root: /home/rubys/svn/rails4/Book/util/work-193/depot

Application Trace | Framework Trace | Full Trace
app/controllers/carts_controller.rb:16:in `show'

Request

Parameters:

{"id"=>"wibble"}

Show session dump

Show env dump

Response

Headers:

None

10.2 Iteration E2: Handling Errors

Log errors and show them on the screen.

Rescue error: log, flash, and redirect.

edit app/controllers/carts_controller.rb
  # GET /carts/1
  # GET /carts/1.xml
  def show
    begin
      @cart = Cart.find(params[:id])
    rescue ActiveRecord::RecordNotFound
      logger.error "Attempt to access invalid cart #{params[:id]}"
      redirect_to store_url, :notice => 'Invalid cart'
    else
      respond_to do |format|
        format.html # show.html.erb
        format.xml  { render :xml => @cart }
      end
    end
  end

Reproduce the error.

get /carts/wibble
You are being redirected.
get http://localhost:3000/

Invalid cart

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95

Inspect the log.

tail -25 log/development.log
  app/controllers/carts_controller.rb:16:in `show'
 
Rendered /home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.6ms)
Rendered /home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (50.8ms)
Rendered /home/rubys/git/rails/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (57.5ms)
 
 
Started GET "/carts/wibble" for 127.0.0.1 at 2010-09-06 10:41:53 -0400
  Processing by CartsController#show as HTML
  Parameters: {"id"=>"wibble"}
  SQL (0.6ms)  *[1m SELECT name
 FROM sqlite_master
 WHERE type = 'table' AND NOT name = 'sqlite_sequence'
*[0m
  Cart Load (0.2ms)  SELECT "carts".* FROM "carts" WHERE ("carts"."id" = 0) LIMIT 1
Attempt to access invalid cart wibble
Redirected to http://localhost:3000/
Completed 302 Found in 52ms
 
 
Started GET "/" for 127.0.0.1 at 2010-09-06 10:41:53 -0400
  Processing by StoreController#index as HTML
  Product Load (0.8ms)  *[1mSELECT "products".* FROM "products" ORDER BY title*[0m
Rendered store/index.html.erb within layouts/application (17.2ms)
Completed 200 OK in 38ms (Views: 21.3ms | ActiveRecord: 1.6ms)

10.3 Iteration E3: Finishing the Cart

Add empty cart button, remove flash for line item create, add totals to view.

Add button to the view.

edit app/views/carts/show.html.erb
<h2>Your Pragmatic Cart</h2>
<ul>    
  <% for item in @cart.line_items %>
    <li><%= item.quantity %> &times; <%= item.product.title %></li>
  <% end %>
</ul>
 
<%= button_to 'Empty cart', @cart, :method => :delete,
    :confirm => 'Are you sure?' %>

Clear session and add flash notice when cart is destroyed.

edit app/controllers/carts_controller.rb
  def destroy
    @cart = Cart.find(params[:id])
    @cart.destroy
    session[:cart_id] = nil
 
    respond_to do |format|
      format.html { redirect_to(store_url,
        :notice => 'Your cart is currently empty') }
      format.xml  { head :ok }
    end
  end

Try it out.

get /carts/1

Your Pragmatic Cart

  • 3 × Programming Ruby 1.9
  • 1 × Web Design for Developers
post /carts/1
You are being redirected.
get http://localhost:3000/

Your cart is currently empty

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
pub depot_h

Remove scaffolding generated flash notice for line item create.

edit app/controllers/line_items_controller.rb
  def create
    @cart = current_cart
    product = Product.find(params[:product_id])
    @line_item = @cart.add_product(product.id)
 
    respond_to do |format|
      if @line_item.save
        format.html { redirect_to(@line_item.cart) }
        format.xml  { render :xml => @line_item,
          :status => :created, :location => @line_item }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @line_item.errors,
          :status => :unprocessable_entity }
      end
    end
  end

Update the view to add totals.

edit app/views/carts/show.html.erb
<div class="cart_title">Your Cart</div>
<table>
  <% for item in @cart.line_items %>
    <tr>
      <td><%= item.quantity %>&times;</td>
      <td><%= item.product.title %></td>
      <td class="item_price"><%= number_to_currency(item.total_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', @cart, :method => :delete,
    :confirm => 'Are you sure?' %>

Add a method to compute the total price of a single line item.

edit app/models/line_item.rb
 
  def total_price
    product.price * quantity
  end

Add a method to compute the total price of the items in the cart.

edit app/models/cart.rb
  def total_price
    line_items.to_a.sum { |item| item.total_price }
  end

Add some style.

edit public/stylesheets/depot.css
/* Styles for the cart in the main page */
 
#store .cart_title {
  font: 120% bold;
}
 
#store .item_price, #store .total_line {
  text-align: right;
}
 
#store .total_line .total_cell {
  font-weight: bold;
  border-top: 1px solid #595;
}

Add a product to the cart, and see the total.

get /

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
post /line_items?product_id=2
You are being redirected.
get http://localhost:3000/carts/2
Your Cart
Web Design for Developers $42.95
Total $42.95

Add a few more products, and watch the totals climb!

post /line_items?product_id=2
You are being redirected.
get http://localhost:3000/carts/2
Your Cart
Web Design for Developers $85.90
Total $85.90
post /line_items?product_id=3
You are being redirected.
get http://localhost:3000/carts/2
Your Cart
Web Design for Developers $85.90
Programming Ruby 1.9 $49.50
Total $135.40

10.4 Playtime

</7 tests, 25 assertions, 0 failures, 0 errors/> expected but was
<"(in /home/rubys/svn/rails4/Book/util/work-193/depot)">.

Traceback:
  /home/rubys/svn/rails4/Book/util/checkdepot.rb:121:in `block in <class:DepotTest>'

Once again, get the tests working, and add tests for the smarter cart.

See that the tests fail.

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_the_truth is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:5:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:20:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!

Substitute names of products and carts for numbers

edit test/fixtures/line_items.yml
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
 
one:
  product: ruby
  cart: one
 
two:
  product: ruby
  cart: one

Update expected target of redirect: Cart#destroy.

edit test/functional/carts_controller_test.rb
  test "should destroy cart" do
    assert_difference('Cart.count', -1) do
      delete :destroy, :id => @cart.to_param
    end
 
    assert_redirected_to store_path
  end

Test both unique and duplicate products.

edit test/unit/cart_test.rb
require 'test_helper'
 
class CartTest < ActiveSupport::TestCase
  test "add unique products" do
    cart = Cart.create
    book_one = products(:one)
    book_two  = products(:two)
    cart.add_product(book_one.id).save!
    cart.add_product(book_two.id).save!
    assert_equal 2, cart.line_items.size
    assert_equal book_one.price + book_two.price, cart.total_price
  end
  
  test "add_duplicate_product" do
    cart = Cart.create
    ruby_book = products(:ruby)
    cart.add_product(ruby_book.id).save!
    cart.add_product(ruby_book.id).save!
    assert_equal 2*book_one.price, cart.total_price
    assert_equal 1, cart.line_items.size
    assert_equal 2, cart.line_items[0].quantity
  end 
end
ruby -I test test/unit/cart_test.rb
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Test run options: --seed 25200
 
Loaded suite test/unit/cart_test
Started
E.
Finished in 1.544584 seconds.
 
  1) Error:
test_add_duplicate_product(CartTest):
NameError: undefined local variable or method `book_one' for #<CartTest:0x90e4b5c>
    test/unit/cart_test.rb:24:in `block in <class:CartTest>'
 
2 tests, 2 assertions, 0 failures, 1 errors, 0 skips
 
Test run options: --seed 25200
pub depot_i

Refactor.

edit test/unit/cart_test.rb
require 'test_helper'
 
class CartTest < ActiveSupport::TestCase
  def setup
    @cart  = Cart.create
    @book_one = products(:ruby)
    @book_two  = products(:two)
  end
  
  test "add unique products" do
    @cart.add_product(@book_one.id).save!
    @cart.add_product(@book_two.id).save!
    assert_equal 2, @cart.line_items.size
    assert_equal @book_one.price + @book_two.price, @cart.total_price
  end
 
  test "add duplicate product" do
    @cart.add_product(@book_one.id).save!
    @cart.add_product(@book_one.id).save!
    assert_equal 2*@book_one.price, @cart.total_price
    assert_equal 1, @cart.line_items.size
    assert_equal 2, @cart.line_items[0].quantity
  end 
end
ruby -I test test/unit/cart_test.rb
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Test run options: --seed 3525
 
Loaded suite test/unit/cart_test
Started
..
Finished in 0.565637 seconds.
 
2 tests, 5 assertions, 0 failures, 0 errors, 0 skips
 
Test run options: --seed 3525

Now do the tests pass? Nope.

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_add_unique_products is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:10:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:20:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!
edit test/functional/products_controller_test.rb
  test "can't delete product in cart" do
    assert_difference('Product.count', 0) do
      delete :destroy, :id => products(:ruby).to_param
    end
 
    assert_redirected_to products_path
  end
 
  test "should destroy product" do
    assert_difference('Product.count', -1) do
      delete :destroy, :id => @product.to_param
    end
 
    assert_redirected_to products_path
  end

Now the tests should pass.

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_add_unique_products is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:10:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:18:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!

Add price to line item

rails generate migration add_price_to_line_item price:decimal
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      invoke  active_record
      create    db/migrate/20100906144246_add_price_to_line_item.rb
edit db/migrate/20100906144246_add_price_to_line_item.rb
class AddPriceToLineItem < ActiveRecord::Migration
  def self.up
    add_column :line_items, :price, :decimal
    LineItem.all.each do |li|
      li.price = li.product.price
    end
  end
 
  def self.down
    remove_column :line_items, :price
  end
end
rake db:migrate
mv 20100906144246_add_price_to_line_item.rb 20100301000006_add_price_to_line_item.rb
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
==  AddPriceToLineItem: migrating =============================================
-- add_column(:line_items, :price, :decimal)
   -> 0.0011s
==  AddPriceToLineItem: migrated (0.1721s) ====================================
 
edit app/models/cart.rb
class Cart < ActiveRecord::Base
  has_many :line_items, :dependent => :destroy
 
  def add_product(product_id)
    current_item = line_items.where(:product_id => product_id).first
    if current_item
      current_item.quantity += 1
    else
      current_item = LineItem.new(:product_id=>product_id)
      current_item.price = current_item.product.price
      line_items << current_item
    end
    current_item
  end
 
  def total_price
    line_items.to_a.sum { |item| item.total_price }
  end
end
git commit -a -m "Adding a Cart"
Created commit 79e18bf: Adding a Cart
 6 files changed, 81 insertions(+), 13 deletions(-)
git tag iteration-d

11.1 Iteration F1: Moving the Cart

Refactor the cart view into partials, and reference the result from the layout.

Create a "partial" view, for just one line item

edit app/views/line_items/_line_item.html.erb
<tr>
  <td><%= line_item.quantity %>&times;</td>
  <td><%= line_item.product.title %></td>
  <td class="item_price"><%= number_to_currency(line_item.total_price) %></td>
</tr>

Replace that portion of the view with a callout to the partial

edit app/views/carts/show.html.erb
<div class="cart_title">Your Cart</div>
<table>
  <%= render(@cart.line_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', @cart, :method => :delete,
    :confirm => 'Are you sure?' %>

Make a copy as a partial for the cart controller

cp app/views/carts/show.html.erb app/views/carts/_cart.html.erb

Modify the copy to reference the (sub)partial and take input from @cart

edit app/views/carts/_cart.html.erb
<div class="cart_title">Your Cart</div>
<table>
  <%= render(cart.line_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', cart, :method => :delete,
    :confirm => 'Are you sure?' %>

Insert a call in the controller to find the cart

edit app/controllers/store_controller.rb
  def index
    @products = Product.all
    @cart = current_cart
  end

Reference the partial from the layout.

edit app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
  <title>Pragprog Books Online Store</title>
  <%= stylesheet_link_tag "scaffold" %>
  <%= stylesheet_link_tag "depot", :media => "all" %>
  <%= javascript_include_tag :defaults %>
  <%= csrf_meta_tag %>
</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 @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">
      <%= yield %>
    </div>
  </div>
</body>
</html>

Add a small bit of style.

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;
}
pub depot_j

Change the redirect to be back to the store.

edit app/controllers/line_items_controller.rb
  def create
    @cart = current_cart
    product = Product.find(params[:product_id])
    @line_item = @cart.add_product(product.id)
 
    respond_to do |format|
      if @line_item.save
        format.html { redirect_to(store_url) }
        format.xml  { render :xml => @line_item,
          :status => :created, :location => @line_item }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @line_item.errors,
          :status => :unprocessable_entity }
      end
    end
  end

Purchase another product.

get /
Your Cart
Web Design for Developers $85.90
Programming Ruby 1.9 $49.50
Total $135.40
Home
Questions
News
Contact

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
post /line_items?product_id=3
You are being redirected.
get http://localhost:3000/
Your Cart
Web Design for Developers $85.90
Programming Ruby 1.9 $99.00
Total $184.90
Home
Questions
News
Contact

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
pub depot_k

11.2 Iteration F2: Creating an AJAX-Based Cart

edit app/views/store/index.html.erb
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
 
<h1>Your Pragmatic Catalog</h1>
 
<% @products.each do |product| %>
  <div class="entry">
    <%= image_tag(product.image_url) %>
    <h3><%= product.title %></h3>
    <%=sanitize product.description %>
    <div class="price_line">
      <span class="price"><%= number_to_currency(product.price) %></span>
      <%= button_to 'Add to Cart', line_items_path(:product_id => product),
        :remote => true %>
    </div>
  </div>
<% end %>
edit app/controllers/line_items_controller.rb
  def create
    @cart = current_cart
    product = Product.find(params[:product_id])
    @line_item = @cart.add_product(product.id)
 
    respond_to do |format|
      if @line_item.save
        format.html { redirect_to(store_url) }
        format.js
        format.xml  { render :xml => @line_item,
          :status => :created, :location => @line_item }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @line_item.errors,
          :status => :unprocessable_entity }
      end
    end
  end
edit app/views/line_items/create.js.rjs
page.replace_html('cart', render(@cart))
pub depot_l

11.3 Iteration F3: Highlighting Changes

edit app/controllers/line_items_controller.rb
  def create
    @cart = current_cart
    product = Product.find(params[:product_id])
    @line_item = @cart.add_product(product.id)
 
    respond_to do |format|
      if @line_item.save
        format.html { redirect_to(store_url) }
        format.js   { @current_item = @line_item }
        format.xml  { render :xml => @line_item,
          :status => :created, :location => @line_item }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @line_item.errors,
          :status => :unprocessable_entity }
      end
    end
  end
edit app/views/line_items/_line_item.html.erb
<% if line_item == @current_item %>
<tr id="current_item">
<% else %>
<tr>
<% end %>
  <td><%= line_item.quantity %>&times;</td>
  <td><%= line_item.product.title %></td>
  <td class="item_price"><%= number_to_currency(line_item.total_price) %></td>
</tr>
edit app/views/line_items/create.js.rjs
page.replace_html('cart', render(@cart))
 
page[:current_item].visual_effect :highlight,
                                  :startcolor => "#88ff88",
                                  :endcolor => "#114411"
pub depot_m

11.4 Iteration F4: Hide an Empty Cart

edit app/views/line_items/create.js.rjs
page.replace_html('cart', render(@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 < ActiveRecord::Base
  has_many :line_items, :dependent => :destroy
 
  def add_product(product_id)
    current_item = line_items.where(:product_id => product_id).first
    if current_item
      current_item.quantity += 1
    else
      current_item = LineItem.new(:product_id=>product_id)
      current_item.price = current_item.product.price
      line_items << current_item
    end
    current_item
  end
 
  def total_price
    line_items.to_a.sum { |item| item.total_price }
  end
 
  def total_items
    line_items.sum(:quantity)
  end
end
ls -p app
controllers/
helpers/
mailers/
models/
views/
ls -p app/helpers
application_helper.rb
carts_helper.rb
line_items_helper.rb
products_helper.rb
store_helper.rb
edit app/views/layouts/application.html.erb
      <%= hidden_div_if(@cart.line_items.empty?, :id => "cart") do %>
        <%= render @cart %>
      <% end %>
edit app/helpers/application_helper.rb
module ApplicationHelper
  def hidden_div_if(condition, attributes = {}, &block)
    if condition
      attributes["style"] = "display: none"
    end
    content_tag("div", attributes, &block)
  end
end
edit app/controllers/carts_controller.rb
  def destroy
    @cart = Cart.find(params[:id])
    @cart.destroy
    session[:cart_id] = nil
 
    respond_to do |format|
      format.html { redirect_to(store_url) }
      format.xml  { head :ok }
    end
  end
pub depot_n
get /carts/2
Your Cart
Web Design for Developers $85.90
Programming Ruby 1.9 $99.00
Total $184.90
Home
Questions
News
Contact
Your Cart
Web Design for Developers $85.90
Programming Ruby 1.9 $99.00
Total $184.90
post /carts/2
You are being redirected.
get http://localhost:3000/
Home
Questions
News
Contact

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
get /
Home
Questions
News
Contact

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
post /line_items?product_id=3
You are being redirected.
get http://localhost:3000/
Your Cart
Programming Ruby 1.9 $49.50
Total $49.50
Home
Questions
News
Contact

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95

Run tests... oops.

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_add_unique_products is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:10:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:18:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!

11.5 Iteration F5: Testing AJAX changes

</8 tests, 29 assertions, 0 failures, 0 errors/> expected but was
<"  test \"should create line_item\" do">.

Traceback:
  /home/rubys/svn/rails4/Book/util/checkdepot.rb:142:in `block in <class:DepotTest>'

Verify that yes, indeed, the product index is broken.

get /products

NoMethodError in Products#index

Showing /home/rubys/svn/rails4/Book/util/work-193/depot/app/views/layouts/application.html.erb where line #21 raised:

undefined method `line_items' for nil:NilClass

Extracted source (around line #21):

18:     <div id="side">
19:       <!-- START_HIGHLIGHT -->
20:       <!-- START:hidden_div -->
21:       <%= hidden_div_if(@cart.line_items.empty?, :id => "cart") do %>
22:         <%= render @cart %>
23:       <% end %>
24:     <!-- END:hidden_div -->

Rails.root: /home/rubys/svn/rails4/Book/util/work-193/depot

Application Trace | Framework Trace | Full Trace
app/views/layouts/application.html.erb:21:in `_app_views_layouts_application_html_erb__794339825_72271100_561062710'
app/controllers/products_controller.rb:7:in `index'

Request

Parameters:

None

Show session dump

Show env dump

Response

Headers:

None

Conditionally display the cart.

edit app/views/layouts/application.html.erb
      <% if @cart %>
        <%= hidden_div_if(@cart.line_items.empty?, :id => "cart") do %>
          <%= render @cart %>
        <% end %>
      <% end %>

Update the redirect test.

edit test/functional/line_items_controller_test.rb
  test "should create line_item" do
    assert_difference('LineItem.count') do
      post :create, :product_id => products(:ruby).id
    end
    assert_redirected_to store_path
  end

Add an AJAX test.

edit test/functional/line_items_controller_test.rb
  test "should create line_item via ajax" do
    assert_difference('LineItem.count') do
      xhr :post, :create, :product_id => products(:ruby).id
    end 
 
    assert_response :success
    assert_select 'tr#current_item', /Programming Ruby 1.9/
  end

Run the tests again.

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_add_unique_products is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:10:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:18:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!

Save our progress

git commit -a -m "AJAX"
Created commit 725a38c: AJAX
 3 files changed, 39 insertions(+), 4 deletions(-)
git tag iteration-g

12.1 Iteration G1: Capturing an Order

rails generate scaffold Order name:string address:text email:string pay_type:string
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      invoke  active_record
      create    db/migrate/20100906144323_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
      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
edit db/migrate/20100906144323_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
rails generate migration add_order_id_to_line_item order_id:integer
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      invoke  active_record
      create    db/migrate/20100906144327_add_order_id_to_line_item.rb
rake db:migrate
mv 20100906144323_create_orders.rb 20100301000007_create_orders.rb
mv 20100906144327_add_order_id_to_line_item.rb 20100301000008_add_order_id_to_line_item.rb
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
==  CreateOrders: migrating ===================================================
-- create_table(:orders)
   -> 0.0019s
==  CreateOrders: migrated (0.0020s) ==========================================
 
==  AddOrderIdToLineItem: migrating ===========================================
-- add_column(:line_items, :order_id, :integer)
   -> 0.0016s
==  AddOrderIdToLineItem: migrated (0.0018s) ==================================
 
sqlite3 db/development.sqlite3 .schema
CREATE TABLE "carts" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime, "updated_at" datetime);
CREATE TABLE "line_items" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "product_id" integer, "cart_id" integer, "created_at" datetime, "updated_at" datetime, "quantity" integer DEFAULT 1, "price" decimal, "order_id" integer);
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), "price" decimal(8,2), "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");
edit app/models/order.rb
class Order < ActiveRecord::Base
  has_many :line_items, :dependent => :destroy
  # ...
end
edit app/models/line_item.rb
edit app/views/carts/_cart.html.erb
<div class="cart_title">Your Cart</div>
<table>
  <%= render(cart.line_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", new_order_url, :method=>:get %>
<%= button_to 'Empty cart', cart, :method => :delete,
    :confirm => 'Are you sure?' %>
edit app/controllers/orders_controller.rb
  def new
    if current_cart.line_items.empty?
      redirect_to store_url, :notice => "Your cart is empty"
      return
    end
 
    @order = Order.new
 
    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @order }
    end
  end
edit app/views/orders/new.html.erb
<div class="depot_form">
  <fieldset>
    <legend>Please Enter Your Details</legend>
<%= render 'form' %>
  </fieldset>
</div>
edit app/views/orders/_form.html.erb
<%= form_for @order do |f| %>
  <% if @order.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@order.errors.count, "error") %>
        prohibited this order from being saved:</h2>
      <ul>
      <% @order.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
 
  <div>
    <%= f.label :name, "Name:" %>
    <%= f.text_field :name, :size => 40 %>
  </div>
 
  <div>
    <%= f.label :address, "Address:" %>
    <%= f.text_area :address, :rows => 3, :cols => 40 %>
  </div>
 
  <div>
    <%= f.label :email, "E-Mail:" %>
    <%= f.email_field :email, :size => 40 %>
  </div>
 
  <div>
    <%= f.label :pay_type, "Pay with:" %>
    <%=
      f.select :pay_type,
                   Order::PAYMENT_TYPES, 
                  :prompt => "Select a payment method"
    %>
  </div>
 
  <%= f.submit "Place Order" %>
<% end %>  
edit app/models/order.rb
class Order < ActiveRecord::Base
  PAYMENT_TYPES = [ "Check", "Credit card", "Purchase order" ]
 
  # ...
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;
}
edit app/models/order.rb
class Order < ActiveRecord::Base
  PAYMENT_TYPES = [ "Check", "Credit card", "Purchase order" ]
 
  validates :name, :address, :email, :pay_type, :presence => true
  validates :pay_type, :inclusion => PAYMENT_TYPES
 
  # ...
edit app/controllers/orders_controller.rb
  def create
    @order = Order.new(params[:order])
    @order.add_line_items_from_cart(current_cart)
 
    respond_to do |format|
      if @order.save
        Cart.destroy(session[:cart_id])
        session[:cart_id] = nil
        format.html { redirect_to(store_url, :notice => 
          'Thank you for your order.') }
        format.xml  { render :xml => @order, :status => :created,
          :location => @order }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @order.errors,
          :status => :unprocessable_entity }
      end
    end
  end
edit app/models/order.rb
class Order < ActiveRecord::Base
  PAYMENT_TYPES = [ "Check", "Credit card", "Purchase order" ]
 
  # ...
  validates :name, :address, :email, :pay_type, :presence => true
  validates :pay_type, :inclusion => PAYMENT_TYPES
 
  # ...
 
 
  has_many :line_items, :dependent => :destroy
  # ...
 
  def add_line_items_from_cart(cart)
    cart.line_items.each do |item|
      item.cart_id = nil
      line_items << item
    end
  end
end
get /orders/new
Please Enter Your Details
post /orders
Please Enter Your Details

5 errors prohibited this order from being saved:

  • Name can't be blank
  • Address can't be blank
  • Email can't be blank
  • Pay type can't be blank
  • Pay type is not included in the list
sqlite3> select * from orders
sqlite3> select * from line_items
        id = 10
product_id = 3
   cart_id = 3
created_at = 2010-09-06 14:42:56.369752
updated_at = 2010-09-06 14:42:56.369752
  quantity = 1
     price = 49.5
  order_id = 
get /orders/new
Please Enter Your Details
post /orders
You are being redirected.
get http://localhost:3000/
Home
Questions
News
Contact

Thank you for your order.

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
sqlite3> select * from orders
        id = 1
      name = Dave Thomas
   address = 123 Main St
     email = customer@example.com
  pay_type = Check
created_at = 2010-09-06 14:43:35.345180
updated_at = 2010-09-06 14:43:35.345180
sqlite3> select * from line_items
        id = 10
product_id = 3
   cart_id = 
created_at = 2010-09-06 14:42:56.369752
updated_at = 2010-09-06 14:43:35.359648
  quantity = 1
     price = 49.5
  order_id = 1
edit app/views/line_items/create.js.rjs
page.select("#notice").each { |notice| notice.hide }
 
page.replace_html('cart', render(@cart))
page[:cart].visual_effect :blind_down if @cart.total_items == 1
page[:current_item].visual_effect :highlight,
                                  :startcolor => "#88ff88",
                                  :endcolor => "#114411"

12.2 Iteration G2: Atom Feeds

Demonstrate various respond_to/format options, as well as "through" relations and basic authentication.

Define a "who_bought" member action

edit app/controllers/products_controller.rb
  def who_bought
    @product = Product.find(params[:id])
    respond_to do |format|
      format.xml { render :xml => @product }
    end
  end

Add to the routes

edit config/routes.rb
Depot::Application.routes.draw do
  resources :orders
 
  resources :line_items
 
  resources :carts
 
  get "store/index"
 
  resources :products do
    get :who_bought, :on => :member
  end
 
 
  # ...
 
  # You can have the root of your site routed with "root"
  # just remember to delete public/index.html.
  # root :to => "welcome#index"
  root :to => 'store#index', :as => 'store'
 
  # ...
end

Try again... success... but not much there

curl --silent --user dave:secret http://localhost:3000/products/3/who_bought.xml
<?xml version="1.0" encoding="UTF-8"?>
<product>
  <created-at type="datetime">2010-09-06T14:39:56Z</created-at>
  <description>&lt;p&gt;
        Ruby is the fastest growing and most exciting dynamic language out
        there. If you need to get working programs delivered fast, you should
        add Ruby to your toolbox.
      &lt;/p&gt;</description>
  <id type="integer">3</id>
  <image-url>/images/ruby.jpg</image-url>
  <price type="decimal">49.5</price>
  <title>Programming Ruby 1.9</title>
  <updated-at type="datetime">2010-09-06T14:39:56Z</updated-at>
</product>

Add "orders" to the Product class

edit app/models/product.rb
class Product < ActiveRecord::Base
  default_scope :order => 'title'
  has_many :line_items
  has_many :orders, :through => :line_items
  #...
end

Define an Atom view (using the Atom builder)

edit app/views/products/who_bought.atom.builder
atom_feed do |feed|
  feed.title "Who bought #{@product.title}"
 
  latest_order = @product.orders.sort_by(&:updated_at).last
  feed.updated( latest_order && latest_order.updated_at )
 
  @product.orders.each do |order|
    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

Add the atom format to the controller

edit app/controllers/products_controller.rb
  def who_bought
    @product = Product.find(params[:id])
    respond_to do |format|
      format.atom
      format.xml { render :xml => @product }
    end
  end

Fetch the Atom feed

curl --silent --user dave:secret http://localhost:3000/products/3/who_bought.atom
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <id>tag:localhost,2005:/products/3/who_bought</id>
  <link rel="alternate" type="text/html" href="http://localhost:3000"/>
  <link rel="self" type="application/atom+xml" href="http://localhost:3000/products/3/who_bought.atom"/>
  <title>Who bought Programming Ruby 1.9</title>
  <updated>2010-09-06T14:43:35Z</updated>
  <entry>
    <id>tag:localhost,2005:Order/1</id>
    <published>2010-09-06T14:43:35Z</published>
    <updated>2010-09-06T14:43:35Z</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>Programming Ruby 1.9</td>
            <td>1</td>
            <td>$49.50</td>
          </tr>
          <tr>
            <th colspan="2">total</th>
            <th>$49.50</th>
          </tr>
        </table>
        <p>Paid by Check</p>
      </div>
    </summary>
    <author>
      <name>Dave Thomas</name>
      <email>customer@example.com</email>
    </author>
  </entry>
</feed>
pub depot_o

Include "orders" in the response

edit app/controllers/products_controller.rb
  def who_bought
    @product = Product.find(params[:id])
    respond_to do |format|
      format.atom
      format.xml { render :xml => @product.to_xml(:include => :orders) }
    end
  end

Fetch the xml, see that the orders are included

curl --silent --user dave:secret http://localhost:3000/products/3/who_bought.xml
<?xml version="1.0" encoding="UTF-8"?>
<product>
  <created-at type="datetime">2010-09-06T14:39:56Z</created-at>
  <description>&lt;p&gt;
        Ruby is the fastest growing and most exciting dynamic language out
        there. If you need to get working programs delivered fast, you should
        add Ruby to your toolbox.
      &lt;/p&gt;</description>
  <id type="integer">3</id>
  <image-url>/images/ruby.jpg</image-url>
  <price type="decimal">49.5</price>
  <title>Programming Ruby 1.9</title>
  <updated-at type="datetime">2010-09-06T14:39:56Z</updated-at>
  <orders type="array">
    <order>
      <address>123 Main St</address>
      <created-at type="datetime">2010-09-06T14:43:35Z</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-09-06T14:43:35Z</updated-at>
    </order>
  </orders>
</product>

Define an HTML view

edit app/views/products/who_bought.html.erb
<h3>People Who Bought <%= @product.title %></h3>
 
<ul>
  <% for order in @product.orders %>
    <li>
      <%= mail_to order.email, order.name %>
    </li>
  <% end %>
</ul>

Add the html format to the controller

edit app/controllers/products_controller.rb
  def who_bought
    @product = Product.find(params[:id])
    respond_to do |format|
      format.html
      format.atom
      format.xml { render :xml => @product.to_xml(:include => :orders) }
    end
  end

See the (raw) HTML

curl --silent --user dave:secret http://localhost:3000/products/3/who_bought
<!DOCTYPE html>
<html>
<head>
  <title>Pragprog Books Online Store</title>
<!-- START:stylesheet -->
  <link href="/depot_application/stylesheets/scaffold.css" media="screen" rel="stylesheet" type="text/css" />
  <link href="/depot_application/stylesheets/depot.css" media="all" rel="stylesheet" type="text/css" />
<!-- END:stylesheet -->
  <script src="/depot_application/javascripts/prototype.js" type="text/javascript"></script>
<script src="/depot_application/javascripts/effects.js" type="text/javascript"></script>
<script src="/depot_application/javascripts/dragdrop.js" type="text/javascript"></script>
<script src="/depot_application/javascripts/controls.js" type="text/javascript"></script>
<script src="/depot_application/javascripts/rails.js" type="text/javascript"></script>
<script src="/depot_application/javascripts/application.js" type="text/javascript"></script>
  <meta name="csrf-param" content="authenticity_token"/>
<meta name="csrf-token" content="ph6j3XkG9YxqyQd132r/vg6bprDoQ70YMudQ9hux+TQ="/>
</head>
<body id="store">
  <div id="banner">
    <img alt="Logo" src="/depot_application/images/logo.png" />
    Pragmatic Bookshelf
  </div>
  <div id="columns">
    <div id="side">
      <!-- START_HIGHLIGHT -->
      <!-- START:hidden_div -->
<!-- START_HIGHLIGHT -->
<!-- END_HIGHLIGHT -->
    <!-- END:hidden_div -->
      <!-- END_HIGHLIGHT -->
 
      <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">
      <h3>People Who Bought Programming Ruby 1.9</h3>
 
<ul>
    <li>
      <a href="mailto:customer@example.com">Dave Thomas</a>
    </li>
</ul>
 
    </div>
  </div>
</body>
</html>

Anything that XML can do, JSON can too...

edit app/controllers/products_controller.rb
  def who_bought
    @product = Product.find(params[:id])
    respond_to do |format|
      format.html
      format.atom
      format.xml { render :xml => @product.to_xml(:include => :orders) }
      format.json { render :json => @product.to_json(:include => :orders) }
    end
  end

Fetch the data in JSON format

curl --silent --user dave:secret http://localhost:3000/products/3/who_bought.json
{"product":{"created_at":"2010-09-06T14:39:56Z","description":"<p>\n        Ruby is the fastest growing and most exciting dynamic language out\n        there. If you need to get working programs delivered fast, you should\n        add Ruby to your toolbox.\n      </p>","id":3,"image_url":"/images/ruby.jpg","price":"49.5","title":"Programming Ruby 1.9","updated_at":"2010-09-06T14:39:56Z","orders":[{"address":"123 Main St","created_at":"2010-09-06T14:43:35Z","email":"customer@example.com","id":1,"name":"Dave Thomas","pay_type":"Check","updated_at":"2010-09-06T14:43:35Z"}]}}

Customize the xml

edit app/views/products/who_bought.xml.builder
xml.order_list(:for_product => @product.title) do
  for o in @product.orders
    xml.order do
      xml.name(o.name)
      xml.email(o.email)
    end
  end
end

Change the rendering to use templates

edit app/controllers/products_controller.rb
  def who_bought
    @product = Product.find(params[:id])
    respond_to do |format|
      format.html
      format.atom
      format.xml
      format.json { render :json => @product.to_json(:include => :orders) }
    end
  end

Fetch the (much streamlined) XML

curl --silent --user dave:secret http://localhost:3000/products/3/who_bought.xml
<order_list for_product="Programming Ruby 1.9">
  <order>
    <name>Dave Thomas</name>
    <email>customer@example.com</email>
  </order>
</order_list>

Consider reducing the number of edits to products_controller

12.3 Iteration G3: Pagination

Add in the will_paginate gem

edit Gemfile
# source 'http://rubygems.org'
 
gem 'rails', :path => "/home/rubys/git/rails" # '3.1.0.beta'
gem "arel", :path => "/home/rubys/git/arel"
 
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
 
gem 'sqlite3-ruby', :require => 'sqlite3'
 
# Use unicorn as the web server
# gem 'unicorn'
 
# Deploy with Capistrano
# gem 'capistrano'
 
# To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
# gem 'ruby-debug'
# gem 'ruby-debug19'
 
# Bundle the extra gems:
# gem 'bj'
# gem 'nokogiri'
# gem 'sqlite3-ruby', :require => 'sqlite3'
# gem 'aws-s3', :require => 'aws/s3'
 
gem 'will_paginate', '>= 3.0.pre'
 
# Bundle gems for the local environment. Make sure to
# put test-only gems in this group so their generators
# and rake tasks are available in development mode:
# group :development, :test do
#   gem 'webrat'
# end

Restart the server.

bundle show
Gems included by the bundle:
  * abstract (1.0.0)
  * actionmailer (3.1.0.beta)
  * actionpack (3.1.0.beta)
  * activemodel (3.1.0.beta)
  * activerecord (3.1.0.beta)
  * activeresource (3.1.0.beta)
  * activesupport (3.1.0.beta)
  * arel (1.0.1 099f1d6)
  * builder (2.1.2)
  * bundler (1.0.0)
  * erubis (2.6.6)
  * i18n (0.4.1)
  * mail (2.2.5)
  * mime-types (1.16)
  * polyglot (0.3.1)
  * rack (1.2.1)
  * rack-mount (0.6.13)
  * rack-test (0.5.4)
  * rails (3.1.0.beta 7c78cc3)
  * railties (3.1.0.beta)
  * rake (0.8.7)
  * sqlite3-ruby (1.3.1)
  * thor (0.14.0)
  * treetop (1.4.8)
  * tzinfo (0.3.23)
  * will_paginate (3.0.pre2)

Load in a few orders

edit script/load_orders.rb
Order.transaction do
  (1..100).each do |i|
    Order.create(:name => "Customer #{i}", :address => "#{i} Main Street",
      :email => "customer-#{i}@example.com", :pay_type => "Check")
  end
end
rails runner script/load_orders.rb
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.

Modify the controller to do pagination

edit app/controllers/orders_controller.rb
  def index
    @orders = Order.paginate :page=>params[:page], :order=>'created_at desc',
      :per_page => 10
 
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @orders }
    end
  end

Add some navigational aids

edit app/views/orders/index.html.erb
<h1>Listing orders</h1>
 
<table>
  <tr>
    <th>Name</th>
    <th>Address</th>
    <th>Email</th>
    <th>Pay type</th>
    <th></th>
    <th></th>
    <th></th>
  </tr>
 
<% @orders.each do |order| %>
  <tr>
    <td><%= order.name %></td>
    <td><%= order.address %></td>
    <td><%= order.email %></td>
    <td><%= order.pay_type %></td>
    <td><%= link_to 'Show', order %></td>
    <td><%= link_to 'Edit', edit_order_path(order) %></td>
    <td><%= link_to 'Destroy', order, :confirm => 'Are you sure?',
              :method => :delete %></td>
  </tr>
<% end %>
</table>
 
<br />
 
<%= link_to 'New Order', new_order_path %>
<p><%= will_paginate @orders %></p>

Show the orders

get /orders

Listing orders

Name Address Email Pay type
Customer 100 100 Main Street customer-100@example.com Check Show Edit Destroy
Customer 99 99 Main Street customer-99@example.com Check Show Edit Destroy
Customer 98 98 Main Street customer-98@example.com Check Show Edit Destroy
Customer 97 97 Main Street customer-97@example.com Check Show Edit Destroy
Customer 96 96 Main Street customer-96@example.com Check Show Edit Destroy
Customer 95 95 Main Street customer-95@example.com Check Show Edit Destroy
Customer 94 94 Main Street customer-94@example.com Check Show Edit Destroy
Customer 93 93 Main Street customer-93@example.com Check Show Edit Destroy
Customer 92 92 Main Street customer-92@example.com Check Show Edit Destroy
Customer 91 91 Main Street customer-91@example.com Check Show Edit Destroy

New Order

12.4 Playtime

</9 tests, 30 assertions, 0 failures, 0 errors/> expected but was
<"(in /home/rubys/svn/rails4/Book/util/work-193/depot)">.

Traceback:
  /home/rubys/svn/rails4/Book/util/checkdepot.rb:181:in `block in <class:DepotTest>'
rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_add_unique_products is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:10:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:18:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!
edit test/functional/orders_controller_test.rb
  test "requires item in cart" do
    get :new
    assert_redirected_to store_path
    assert_equal flash[:notice], 'Your cart is empty'
  end
 
  test "should get new" do
    cart = Cart.create
    session[:cart_id] = cart.id
    LineItem.create(:cart => cart, :product => products(:ruby))
 
    get :new
    assert_response :success
  end
edit test/functional/orders_controller_test.rb
require 'test_helper'
 
class OrdersControllerTest < ActionController::TestCase
  # ...
  test "should create order" do
    assert_difference('Order.count') do
      post :create, :order => @order.attributes
    end
 
    assert_redirected_to store_path
  end
end

Update the test data in the fixture

edit test/fixtures/orders.yml
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
 
one:
  name: Dave Thomas
  address: MyText
  email: dave@example.org
  pay_type: Check
 
two:
  name: MyString
  address: MyText
  email: MyString
  pay_type: MyString

move a line item from a cart to an order

edit test/fixtures/line_items.yml
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
 
one:
  product: ruby
  order: one
 
two:
  product: ruby
  cart: one
rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_add_unique_products is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:10:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_index is already defined in ProductsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:18:in `<class:ProductsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/products_controller_test.rb:4:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals!
git commit -a -m "Orders"
Created commit 9fe176b: Orders
 7 files changed, 83 insertions(+), 22 deletions(-)
git tag iteration-h

12.7 Iteration J2: Email Notifications

rails generate mailer Notifier order_received order_shipped
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      create  app/mailers/notifier.rb
      invoke  erb
      create    app/views/notifier
      create    app/views/notifier/order_received.text.erb
      create    app/views/notifier/order_shipped.text.erb
      invoke  test_unit
      create    test/functional/notifier_test.rb
pub depot_p
edit app/mailers/notifier.rb
class Notifier < ActionMailer::Base
  default :from => 'Sam Ruby <depot@example.com>'
 
  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.notifier.order_received.subject
  #
  def order_received(order)
    @order = order
 
    mail :to => order.email, :subject => 'Pragmatic Store Order Confirmation'
  end
 
  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.notifier.order_shipped.subject
  #
  def order_shipped(order)
    @order = order
 
    mail :to => order.email, :subject => 'Pragmatic Store Order Shipped'
  end
end

Tailor the confirm receipt email

edit app/views/notifier/order_received.text.erb
Dear <%= @order.name %>
 
Thank you for your recent order from The Pragmatic Store.
 
You ordered the following items:
 
<%= render @order.line_items %>
 
We'll send you a separate e-mail when your order ships.

Text partial for the line items

edit app/views/line_items/_line_item.text.erb
<%= sprintf("%2d x %s",
            line_item.quantity,
            truncate(line_item.product.title, :length => 50)) %>

HTML partial for the line items

edit app/views/line_items/_line_item.html.erb
<% if line_item == @current_item %>
<tr id="current_item">
<% else %>
<tr>
<% end %>
  <td><%= line_item.quantity %>&times;</td>
  <td><%= line_item.product.title %></td>
  <td class="item_price"><%= number_to_currency(line_item.total_price) %></td>
</tr>

Tailor the confirm shipped email

edit app/views/notifier/order_shipped.html.erb
<h3>Pragmatic Order Shipped</h3>
<p>
  This is just to let you know that we've shipped your recent order:
</p>
 
<table>
  <tr><th colspan="2">Qty</th><th>Description</th></tr>
<%= render @order.line_items %>
</table>

Update the test case

Not helpful: 'Hi, find me in app'

edit test/functional/notifier_test.rb
require 'test_helper'
 
class NotifierTest < ActionMailer::TestCase
  test "order_received" do
    mail = Notifier.order_received(orders(:one))
    assert_equal "Pragmatic Store Order Confirmation", mail.subject
    assert_equal ["dave@example.org"], mail.to
    assert_equal ["depot@example.com"], mail.from
    assert_match /1 x Programming Ruby 1.9/, mail.body.encoded
  end
 
  test "order_shipped" do
    mail = Notifier.order_shipped(orders(:one))
    assert_equal "Pragmatic Store Order Shipped", mail.subject
    assert_equal ["dave@example.org"], mail.to
    assert_equal ["depot@example.com"], mail.from
    assert_match /<td>1&times;<\/td>\s*<td>Programming Ruby 1.9<\/td>/,
      mail.body.encoded
  end
 
end
rake db:test:load
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
ruby -I test test/functional/notifier_test.rb
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Test run options: --seed 19399
 
Loaded suite test/functional/notifier_test
Started
..
Finished in 0.596119 seconds.
 
2 tests, 8 assertions, 0 failures, 0 errors, 0 skips
 
Test run options: --seed 19399

12.8 Iteration J3: Integration Tests

</3 tests, \d+ assertions, 0 failures, 0 errors/> expected but was
<"  def create">.

Traceback:
  /home/rubys/svn/rails4/Book/util/checkdepot.rb:197:in `block in <class:DepotTest>'
edit app/controllers/orders_controller.rb
  def create
    @order = Order.new(params[:order])
    @order.add_line_items_from_cart(current_cart)
 
    respond_to do |format|
      if @order.save
        Cart.destroy(session[:cart_id])
        session[:cart_id] = nil
        Notifier.order_received(@order).deliver
        format.html { redirect_to(store_url, :notice => 
          'Thank you for your order.') }
        format.xml  { render :xml => @order, :status => :created,
          :location => @order }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @order.errors,
          :status => :unprocessable_entity }
      end
    end
  end
rails generate integration_test user_stories
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      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)
 
    get "/"
    assert_response :success
    assert_template "index"
    
    xml_http_request :post, '/line_items', :product_id => ruby_book.id
    assert_response :success 
    
    cart = Cart.find(session[:cart_id])
    assert_equal 1, cart.line_items.size
    assert_equal ruby_book, cart.line_items[0].product
    
    get "/orders/new"
    assert_response :success
    assert_template "new"
    
    post_via_redirect "/orders",
                      :order => { :name     => "Dave Thomas",
                                 :address  => "123 The Street",
                                 :email    => "dave@example.com",
                                 :pay_type => "Check" }
    assert_response :success
    assert_template "index"
    cart = Cart.find(session[:cart_id])
    assert_equal 0, cart.line_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
 
    mail = ActionMailer::Base.deliveries.last
    assert_equal ["dave@example.com"], mail.to
    assert_equal 'Sam Ruby <depot@example.com>', mail[:from].value
    assert_equal "Pragmatic Store Order Confirmation", mail.subject
  end
end
rake test:integration
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_buying_a_product is already defined in UserStoriesTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:11:in `<class:UserStoriesTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
rake aborted!
Command failed with status (1): [/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/...]

    
(See full trace by running task with --trace)
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 => "Credit card"
  }
  
  
    
  def setup
    LineItem.delete_all
    Order.delete_all
    @ruby_book = products(:ruby)
    @rails_book = products(:two)
  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 "/"
    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 :post, '/line_items', :product_id => product.id
        assert_response :success 
      end
    
      def user.has_a_cart_containing(*products)
        cart = Cart.find(session[:cart_id])
        assert_equal products.size, cart.line_items.size
        for item in cart.line_items
          assert products.include?(item.product)
        end
      end
    
      def user.checks_out(details)
        get "/orders/new"
        assert_response :success
        assert_template "new"
 
       post_via_redirect "/orders",
                          :order => { :name     => details[:name],
                                     :address  => details[:address],
                                     :email    => details[:email],
                                     :pay_type => details[:pay_type]
                                    }
        assert_response :success
        assert_template "index"
        cart = Cart.find(session[:cart_id])
        assert_equal 0, cart.line_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
 
    mail = ActionMailer::Base.deliveries.last
    assert_equal order.email,           mail[:to].value
    for line_item in order.line_items
      assert_operator mail.body.to_s, :include?, line_item.product.title
    end
  end
end
rake test:integration
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/dsl_user_stories_test.rb:8: warning: already initialized constant DAVES_DETAILS
/home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/dsl_user_stories_test.rb:16: warning: already initialized constant MIKES_DETAILS
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_buying_a_product is already defined in UserStoriesTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:11:in `<class:UserStoriesTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
rake aborted!
Command failed with status (1): [/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/...]

    
(See full trace by running task with --trace)
git commit -a -m "Admin"
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	app/controllers/carts_controller.rb
#	app/controllers/line_items_controller.rb
#	app/controllers/orders_controller.rb
#	app/controllers/store_controller.rb
#	app/helpers/carts_helper.rb
#	app/helpers/line_items_helper.rb
#	app/helpers/orders_helper.rb
#	app/helpers/store_helper.rb
#	app/mailers/
#	app/models/cart.rb
#	app/models/line_item.rb
#	app/models/order.rb
#	app/views/carts/
#	app/views/line_items/
#	app/views/notifier/
#	app/views/orders/
#	app/views/products/who_bought.atom.builder
#	app/views/products/who_bought.html.erb
#	app/views/products/who_bought.xml.builder
#	app/views/store/
#	db/migrate/20100301000002_create_carts.rb
#	db/migrate/20100301000003_create_line_items.rb
#	db/migrate/20100301000004_add_quantity_to_line_item.rb
#	db/migrate/20100301000005_combine_items_in_cart.rb
#	db/migrate/20100301000006_add_price_to_line_item.rb
#	db/migrate/20100301000007_create_orders.rb
#	db/migrate/20100301000008_add_order_id_to_line_item.rb
#	script/load_orders.rb
#	test/fixtures/carts.yml
#	test/fixtures/line_items.yml
#	test/fixtures/orders.yml
#	test/functional/carts_controller_test.rb
#	test/functional/line_items_controller_test.rb
#	test/functional/notifier_test.rb
#	test/functional/orders_controller_test.rb
#	test/functional/store_controller_test.rb
#	test/integration/
#	test/unit/cart_test.rb
#	test/unit/helpers/carts_helper_test.rb
#	test/unit/helpers/line_items_helper_test.rb
#	test/unit/helpers/orders_helper_test.rb
#	test/unit/helpers/store_helper_test.rb
#	test/unit/line_item_test.rb
#	test/unit/order_test.rb
nothing added to commit but untracked files present (use "git add" to track)
git tag iteration-j
pub depot_q

13.1 Iteration H1: Adding Users

rails generate scaffold User name:string hashed_password:string salt:string
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      invoke  active_record
      create    db/migrate/20100906144454_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
      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
rake db:migrate
mv 20100906144454_create_users.rb 20100301000009_create_users.rb
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
==  CreateUsers: migrating ====================================================
-- create_table(:users)
   -> 0.0018s
==  CreateUsers: migrated (0.0019s) ===========================================
 
edit app/models/user.rb
require 'digest/sha2'
 
class User < ActiveRecord::Base
  validates :name, :presence => true, :uniqueness => true
 
  validates :password, :confirmation => true
  attr_accessor :password_confirmation
  attr_reader   :password
 
  validate  :password_must_be_present
  
  class << self
    def authenticate(name, password)
      if user = find_by_name(name)
        if user.hashed_password == encrypt_password(password, user.salt)
          user
        end
      end
    end
 
    def encrypt_password(password, salt)
      Digest::SHA2.hexdigest(password + "wibble" + salt)
    end
  end
  
  # 'password' is a virtual attribute
  def password=(password)
    @password = password
 
    if password.present?
      generate_salt
      self.hashed_password = self.class.encrypt_password(password, salt)
    end
  end
  
  private
 
    def password_must_be_present
      errors.add(:password, "Missing password") unless hashed_password.present?
    end
  
    def generate_salt
      self.salt = self.object_id.to_s + rand.to_s
    end
end
edit app/controllers/users_controller.rb
  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
edit app/controllers/users_controller.rb
  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
edit app/controllers/users_controller.rb
  def index
    @users = User.order(:name)
 
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @users }
    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/_form.html.erb
<div class="depot_form">
 
<%= form_for @user do |f| %>
  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %>
        prohibited this user from being saved:</h2>
      <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
 
  <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 %>
  </div>
 
  </fieldset>
<% end %>
 
</div>
get /users

Listing users

Name

New User
get /users/new

New user

Enter User Details
:
:
:
Back
post /users
You are being redirected.
get http://localhost:3000/users

Listing users

Name
dave Show Edit Destroy

New User
sqlite3> select * from users
             id = 1
           name = dave
hashed_password = 71cd4304bec2cd51ad9a26ec65f3a90f19661c08d881c45d75210c030da261e9
           salt = 741250600.1346022327762778
     created_at = 2010-09-06 14:44:59.684387
     updated_at = 2010-09-06 14:44:59.684387

13.2 Iteration H2: Authenticating Users

rails generate controller sessions new create destroy
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      create  app/controllers/sessions_controller.rb
       route  get "sessions/destroy"
       route  get "sessions/create"
       route  get "sessions/new"
      invoke  erb
      create    app/views/sessions
      create    app/views/sessions/new.html.erb
      create    app/views/sessions/create.html.erb
      create    app/views/sessions/destroy.html.erb
      invoke  test_unit
      create    test/functional/sessions_controller_test.rb
      invoke  helper
      create    app/helpers/sessions_helper.rb
      invoke    test_unit
      create      test/unit/helpers/sessions_helper_test.rb
rails generate controller admin index
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      create  app/controllers/admin_controller.rb
       route  get "admin/index"
      invoke  erb
      create    app/views/admin
      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/sessions_controller.rb
class SessionsController < ApplicationController
  def new
  end
 
  def create
    if user = User.authenticate(params[:name], params[:password])
      session[:user_id] = user.id
      redirect_to admin_url
    else
      redirect_to login_url, :alert => "Invalid user/password combination"
    end
  end
 
  def destroy
    session[:user_id] = nil
    redirect_to store_url, :notice => "Logged out"
  end
 
end
edit app/views/sessions/new.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") %>.
edit app/controllers/admin_controller.rb
class AdminController < ApplicationController
  def index
    @total_orders = Order.count
  end
 
end
edit config/routes.rb
Depot::Application.routes.draw do
  get 'admin' => 'admin#index'
 
  controller :sessions do
    get  'login' => :new
    post 'login' => :create
    delete 'logout' => :destroy
  end
 
 
  resources :users
 
  resources :orders
 
  resources :line_items
 
  resources :carts
 
  get "store/index"
  resources :products do
    get :who_bought, :on => :member
  end
 
 
  # ...
 
  # You can have the root of your site routed with "root"
  # just remember to delete public/index.html.
  # root :to => "welcome#index"
  root :to => 'store#index', :as => 'store'
 
  # ...
end
get /login
Please Log In
post /login
You are being redirected.
get http://localhost:3000/admin

Welcome

It's 2010-09-06 10:45:10 -0400 We have 101 orders.

13.3 Iteration H3: Limiting Access

edit app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_filter :authorize
 
    # ...
 
  protected
 
    def authorize
      unless User.find_by_id(session[:user_id])
        redirect_to login_url, :notice => "Please log in"
      end
    end
end
edit app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  skip_before_filter :authorize
edit app/controllers/store_controller.rb
class StoreController < ApplicationController
  skip_before_filter :authorize
edit app/controllers/carts_controller.rb
class CartsController < ApplicationController
    skip_before_filter :authorize, :only => [:create, :update, :delete]
 
edit app/controllers/line_items_controller.rb
class LineItemsController < ApplicationController
    skip_before_filter :authorize, :only => :create
 
edit app/controllers/orders_controller.rb
class OrdersController < ApplicationController
    skip_before_filter :authorize, :only => [:new, :create]
 
edit app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
  <title>Pragprog Books Online Store</title>
  <%= stylesheet_link_tag "scaffold" %>
  <%= stylesheet_link_tag "depot", :media => "all" %>
  <%= javascript_include_tag :defaults %>
  <%= csrf_meta_tag %>
</head>
<body id="store">
  <div id="banner">
    <%= image_tag("logo.png") %>
    <%= @page_title || "Pragmatic Bookshelf" %>
  </div>
  <div id="columns">
    <div id="side">
      <% if @cart %>
        <%= hidden_div_if(@cart.line_items.empty?, :id => "cart") do %>
          <%= render @cart %>
        <% end %>
      <% end %>
 
      <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 />
 
      <% if session[:user_id] %>
        <br />
        <%= link_to 'Orders',   orders_path   %><br />
        <%= link_to 'Products', products_path %><br />
        <%= link_to 'Users',    users_path    %><br />
        <br />
        <%= button_to 'Logout', logout_path, :method => :delete   %>
      <% end %>
    </div>
    <div id="main">
      <%= yield %>
    </div>
  </div>
</body>
</html>
pub depot_r
get /admin

Welcome

It's 2010-09-06 10:45:11 -0400 We have 101 orders.
post /logout
You are being redirected.
get http://localhost:3000/
Home
Questions
News
Contact

Logged out

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
get /
Home
Questions
News
Contact

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
get /products
You are being redirected.
get http://localhost:3000/login
Please Log In
get /login
Please Log In
post /login
You are being redirected.
get http://localhost:3000/admin

Welcome

It's 2010-09-06 10:45:13 -0400 We have 101 orders.
get /products

Listing products

Debug
Debug It!
Professional programmers develop a knack of unerringly zeroing in on...
Show
Edit
Destroy
Ruby
Programming Ruby 1.9
Ruby is the fastest growing and most exciting dynamic language out ...
Show
Edit
Destroy
Wd4d
Web Design for Developers
Web Design for Developers will show you how to make your web-b...
Show
Edit
Destroy

New product
get /users

Listing users

Name
dave Show Edit Destroy

New User

13.4 Iteration H4: Adding a Sidebar

edit app/models/user.rb
require 'digest/sha2'
 
class User < ActiveRecord::Base
  validates :name, :presence => true, :uniqueness => true
 
  validates :password, :confirmation => true
  attr_accessor :password_confirmation
  attr_reader   :password
 
  validate  :password_must_be_present
  
  class << self
    def authenticate(name, password)
      if user = find_by_name(name)
        if user.hashed_password == encrypt_password(password, user.salt)
          user
        end
      end
    end
 
    def encrypt_password(password, salt)
      Digest::SHA2.hexdigest(password + "wibble" + salt)
    end
  end
  
  # 'password' is a virtual attribute
  def password=(password)
    @password = password
 
    if password.present?
      generate_salt
      self.hashed_password = self.class.encrypt_password(password, salt)
    end
  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_must_be_present
      errors.add(:password, "Missing password") unless hashed_password.present?
    end
  
    def generate_salt
      self.salt = self.object_id.to_s + rand.to_s
    end
end
edit app/controllers/users_controller.rb
class UsersController < ApplicationController
  # GET /users
  # GET /users.xml
  def index
    @users = User.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/views/users/index.html.erb
<h1>Listing users</h1>
 
<p id="notice"><%= notice %></p>
 
<!-- ... -->

13.5 Playtime

</10 tests, 31 assertions, 0 failures, 0 errors/> expected but was
<"(in /home/rubys/svn/rails4/Book/util/work-193/depot)">.

Traceback:
  /home/rubys/svn/rails4/Book/util/checkdepot.rb:226:in `block in <class:DepotTest>'

See that requiring a login causes most tests to fail (good!)

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_add_unique_products is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:10:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_new is already defined in SessionsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/sessions_controller_test.rb:4:in `<class:SessionsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/sessions_controller_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/dsl_user_stories_test.rb:8: warning: already initialized constant DAVES_DETAILS
/home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/dsl_user_stories_test.rb:16: warning: already initialized constant MIKES_DETAILS
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_buying_a_product is already defined in UserStoriesTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:11:in `<class:UserStoriesTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals, test:integration!

Cause all tests to do an implicit login

edit test/test_helper.rb
class ActiveSupport::TestCase
  # ...
 
  # Add more helper methods to be used by all tests here...
  def login_as(user)
    session[:user_id] = users(user).id
  end
 
  def logout
    session.delete :user_id
  end
 
  def setup
    login_as :one if defined? session
  end
end

First, lets fix the sessions controller test

edit test/functional/sessions_controller_test.rb
require 'test_helper'
 
class SessionsControllerTest < ActionController::TestCase
  test "should get new" do
    get :new
    assert_response :success
  end
 
  test "should login" do
    dave = users(:one)
    post :create, :name => dave.name, :password => 'secret'
    assert_redirected_to admin_url
    assert_equal dave.id, session[:user_id]
  end
 
  test "should fail login" do
    dave = users(:one)
    post :create, :name => dave.name, :password => 'wrong'
    assert_redirected_to login_url
  end
 
  test "should logout" do
    delete :destroy
    assert_redirected_to store_url
  end
 
end
edit test/fixtures/users.yml
<% SALT = "NaCl" unless defined?(SALT) %>
 
one:
  name: dave
  hashed_password: <%= User.encrypt_password('secret', SALT) %>
  salt: <%= SALT %>
 
two:
  name: MyString
  hashed_password: MyString
  salt: MyString
ruby -I test test/functional/sessions_controller_test.rb
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Test run options: --seed 9963
 
Loaded suite test/functional/sessions_controller_test
Started
....
Finished in 0.177750 seconds.
 
4 tests, 5 assertions, 0 failures, 0 errors, 0 skips
 
Test run options: --seed 9963
edit test/functional/users_controller_test.rb
require 'test_helper'
 
class UsersControllerTest < ActionController::TestCase
  setup do
    @input_attributes = {
      :name                  => "sam",
      :password              => "private",
      :password_confirmation => "private"
    }
 
    @user = users(:one)
  end
  #...
  test "should create user" do
    assert_difference('User.count') do
      post :create, :user => @input_attributes
    end
 
    assert_redirected_to users_path
  end
  #...
  test "should update user" do
    put :update, :id => @user.to_param, :user => @input_attributes
    assert_redirected_to users_path
  end
end
rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_add_unique_products is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:10:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_new is already defined in SessionsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/sessions_controller_test.rb:4:in `<class:SessionsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/sessions_controller_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/dsl_user_stories_test.rb:8: warning: already initialized constant DAVES_DETAILS
/home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/dsl_user_stories_test.rb:16: warning: already initialized constant MIKES_DETAILS
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_buying_a_product is already defined in UserStoriesTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:11:in `<class:UserStoriesTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals, test:integration!

Try requesting the xml... see auth failure.

curl --silent http://localhost:3000/products/3/who_bought.xml
<html><body>You are being <a href="http://localhost:3000/login">redirected</a>.</body></html>

Is this the best way to detect request format?

Enable basic auth

edit app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_filter :authorize
 
    # ...
 
  protected
 
    def authorize
      if request.format == Mime::HTML 
        unless User.find_by_id(session[:user_id])
          redirect_to login_url, :notice => "Please log in"
        end
      else
        authenticate_or_request_with_http_basic do |username, password|
          User.authenticate(username, password)
        end
      end
    end

Try requesting the xml... see auth succeed.

curl --silent --user dave:secret http://localhost:3000/products/3/who_bought.xml
<order_list for_product="Programming Ruby 1.9">
  <order>
    <name>Dave Thomas</name>
    <email>customer@example.com</email>
  </order>
</order_list>

14.1 Playtime

rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_add_unique_products is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:10:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_new is already defined in SessionsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/sessions_controller_test.rb:4:in `<class:SessionsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/sessions_controller_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/dsl_user_stories_test.rb:8: warning: already initialized constant DAVES_DETAILS
/home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/dsl_user_stories_test.rb:16: warning: already initialized constant MIKES_DETAILS
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_buying_a_product is already defined in UserStoriesTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:11:in `<class:UserStoriesTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals, test:integration!
git commit -a -m "formats"
Created commit 3408c3d: formats
 5 files changed, 77 insertions(+), 11 deletions(-)
git tag iteration-i

15.1 Task I1: Selecting the locale

Define the default and available languages.

edit config/initializers/i18n.rb
#encoding: utf-8
I18n.default_locale = :en
 
LANGUAGES = [
  ['English',                  'en'],
  ["Espa&ntilde;ol".html_safe, 'es']
]

Restart the server.

edit app/views/layouts/application.html.erb
    <%= form_tag store_path, :class => 'locale' do %>
      <%= select_tag 'set_locale', 
        options_for_select(LANGUAGES, I18n.locale.to_s),
        :onchange => 'this.form.submit()' %>
      <%= submit_tag 'submit' %>
      <%= javascript_tag "$$('.locale input').each(Element.hide)" %>
    <% end %>

Scope selected routes based on locale. Important: move to bottom!

edit config/routes.rb
Depot::Application.routes.draw do
  get 'admin' => 'admin#index'
  controller :sessions do
    get  'login' => :new
    post 'login' => :create
    delete 'logout' => :destroy
  end
  scope '(:locale)' do
    resources :users
    resources :orders
    resources :line_items
    resources :carts
    resources :products do
      get :who_bought, :on => :member
    end
    root :to => 'store#index', :as => 'store'
  end
end

Default locale parameter, and set locale based on locale parameter.

edit app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_filter :set_i18n_locale_from_params
  # ...
  protected
    def set_i18n_locale_from_params
      if params[:locale]
        if I18n.available_locales.include?(params[:locale].to_sym)
          I18n.locale = params[:locale]
        else
          flash.now[:notice] = 
            "#{params[:locale]} translation not available"
          logger.error flash.now[:notice]
        end
      end
 
    end
 
    def default_url_options
      { :locale => I18n.locale }
    end
end

Verify that the routes work.

get /en
Home
Questions
News
Contact

Orders
Products
Users

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
get /es
Home
Questions
News
Contact

Orders
Products
Users

es translation not available

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95

Replace translatable text with calls out to translation functions.

edit app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
  <title>Pragprog Books Online Store</title>
  <%= stylesheet_link_tag "scaffold" %>
  <%= stylesheet_link_tag "depot", :media => "all" %>
  <%= javascript_include_tag :defaults %>
  <%= csrf_meta_tag %>
</head>
<body id="store">
  <div id="banner">
    <%= form_tag store_path, :class => 'locale' do %>
      <%= select_tag 'set_locale', 
        options_for_select(LANGUAGES, I18n.locale.to_s),
        :onchange => 'this.form.submit()' %>
      <%= submit_tag 'submit' %>
      <%= javascript_tag "$$('.locale input').each(Element.hide)" %>
    <% end %>
    <%= image_tag("logo.png") %>
    <%= @page_title || t('.title') %>
  </div>
  <div id="columns">
    <div id="side">
      <% if @cart %>
        <%= hidden_div_if(@cart.line_items.empty?, :id => "cart") do %>
          <%= render @cart %>
        <% end %>
      <% end %>
 
      <a href="http://www...."><%= t('.home') %></a><br />
      <a href="http://www..../faq"><%= t('.questions') %></a><br />
      <a href="http://www..../news"><%= t('.news') %></a><br />
      <a href="http://www..../contact"><%= t('.contact') %></a><br />
 
      <% if session[:user_id] %>
        <br />
        <%= link_to 'Orders',   orders_path   %><br />
        <%= link_to 'Products', products_path %><br />
        <%= link_to 'Users',    users_path    %><br />
        <br />
        <%= button_to 'Logout', logout_path, :method => :delete   %>
      <% end %>
    </div>
    <div id="main">
      <%= yield %>
    </div>
  </div>
</body>
</html>

Replace translatable text with calls out to translation functions.

cp -r /home/rubys/svn/rails4/Book/util/data/i18n/*.yml config/locales

Define some translations for the layout.

edit config/locales/en.yml
en:
 
  layouts:
    application:
      title:       "Pragmatic Bookshelf"
      home:        "Home"
      questions:   "Questions"
      news:        "News"
      contact:     "Contact"
edit config/locales/es.yml
es:
 
  layouts:
    application:
      title:       "Publicaciones de Pragmatic"
      home:        "Inicio"
      questions:   "Preguntas"
      news:        "Noticias"
      contact:     "Contacto"

Format the currency.

edit config/locales/es.yml
es:
 
  number:
    currency:
      format:
        unit:      "$US"
        precision: 2
        separator: ","
        delimiter: "."
        format:    "%n&nbsp;%u"

Server needs to be restarted when introducting a new language

Restart the server.

See results

get /es
Inicio
Preguntas
Noticias
Contacto

Orders
Products
Users

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

34,95 $US
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

49,50 $US
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

42,95 $US

Replace translatable text with calls out to translation functions.

edit app/views/store/index.html.erb
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
 
<h1><%= t('.title_html') %></h1>
 
<% @products.each do |product| %>
  <div class="entry">
    <%= image_tag(product.image_url) %>
    <h3><%= product.title %></h3>
    <%=sanitize product.description %>
    <div class="price_line">
      <span class="price"><%= number_to_currency(product.price) %></span>
      <%= button_to t('.add'), line_items_path(:product_id => product),
        :remote => true %>
    </div>
  </div>
<% end %>

Define some translations for the main page.

edit config/locales/en.yml
en:
 
  store:
    index:
      title_html:  "Your Pragmatic Catalog"
      add:         "Add to Cart"
edit config/locales/es.yml
es:
 
  store:
    index:
      title_html:  "Su Cat&aacute;logo de Pragmatic"
      add:         "A&ntilde;adir al Carrito"

See results

get /es
Inicio
Preguntas
Noticias
Contacto

Orders
Products
Users

Su Catálogo de Pragmatic

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

34,95 $US
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

49,50 $US
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

42,95 $US

15.2 Task I2: translating the store front

Replace translatable text with calls out to translation functions.

edit app/views/carts/_cart.html.erb
<div class="cart_title"><%= t('.title') %></div>
<table>
  <%= render(cart.line_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 t('.checkout'), new_order_url, :method=>:get %>
<%= button_to t('.empty'), cart, :method => :delete,
    :confirm => 'Are you sure?' %>

Define some translations for the cart.

edit config/locales/en.yml
en:
 
  carts:
    cart:
      title:       "Your Cart"
      empty:       "Empty cart"
      checkout:    "Checkout"
edit config/locales/es.yml
es:
 
  carts:
    cart:
      title:       "Carrito de la Compra"
      empty:       "Vaciar Carrito"
      checkout:    "Comprar"

Add to Cart

get /es
Inicio
Preguntas
Noticias
Contacto

Orders
Products
Users

Su Catálogo de Pragmatic

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

34,95 $US
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

49,50 $US
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

42,95 $US
post /es/line_items?product_id=2
You are being redirected.
get http://localhost:3000/es
Carrito de la Compra
Web Design for Developers 42,95 $US
Total 42,95 $US
Inicio
Preguntas
Noticias
Contacto

Orders
Products
Users

Su Catálogo de Pragmatic

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

34,95 $US
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

49,50 $US
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

42,95 $US

15.3 Task I3: Translating Checkout

Replace translatable text with calls out to translation functions.

edit app/views/orders/new.html.erb
<div class="depot_form">
  <fieldset>
    <legend><%= t('.legend') %></legend>
<%= render 'form' %>
  </fieldset>
</div>
edit app/views/orders/_form.html.erb
<%= form_for @order do |f| %>
  <% if @order.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@order.errors.count, "error") %>
        prohibited this order from being saved:</h2>
      <ul>
      <% @order.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
 
  <div>
    <%= f.label :name, t('.name') + ":" %>
    <%= f.text_field :name, :size => 40 %>
  </div>
 
  <div>
    <%= f.label :address, t('.address') + ":" %>
    <%= f.text_area :address, :rows => 3, :cols => 40 %>
  </div>
 
  <div>
    <%= f.label :email, t('.email') + ":" %>
    <%= f.email_field :email, :size => 40 %>
  </div>
 
  <div>
    <%= f.label :pay_type, t('.pay_type') + ":" %>
    <%=
      f.select :pay_type,
                   Order::PAYMENT_TYPES, 
                  :prompt => t('.pay_prompt')
    %>
  </div>
 
  <%= f.submit t('.submit') %>
<% end %>  

Define some translations for the new order.

edit config/locales/en.yml
en:
 
  orders:
    new:
      legend:      "Please Enter your Details"
    form:
      name:        "Name"
      address:     "Address"
      email:       "E-mail"
      pay_type:    "Pay with"
      pay_prompt:  "Select a payment method"
      submit:      "Place Order"
edit config/locales/es.yml
es:
 
  orders:
    new:
      legend:      "Por favor, introduzca sus datos"
    form:
      name:        "Nombre"
      address:     "Direcci&oacute;n"
      email:       "E-mail"
      pay_type:    "Pagar con"
      pay_prompt:  "Seleccione un m&eacute;todo de pago"
      submit:      "Realizar Pedido"
pub depot_s
edit app/views/orders/_form.html.erb
<%= form_for @order do |f| %>
  <% if @order.errors.any? %>
    <div id="error_explanation">
      <%= t('errors.template.header', :count=>@order.errors.size,
        :model=>t('activerecord.models.order')) %>:
      <ul>
      <% @order.errors.full_messages.each do |msg| %>
        <li><%=raw msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
<!-- ... -->
 
  <div>
    <%= f.label :name, t('.name') + ":" %>
    <%= f.text_field :name, :size => 40 %>
  </div>
 
  <div>
    <%= f.label :address, t('.address') + ":" %>
    <%= f.text_area :address, :rows => 3, :cols => 40 %>
  </div>
 
  <div>
    <%= f.label :email, t('.email') + ":" %>
    <%= f.email_field :email, :size => 40 %>
  </div>
 
  <div>
    <%= f.label :pay_type, t('.pay_type') + ":" %>
    <%=
      f.select :pay_type,
                   Order::PAYMENT_TYPES, 
                  :prompt => t('.pay_prompt')
    %>
  </div>
 
  <%= f.submit t('.submit') %>
<% end %>  

Add to cart

get /es
Carrito de la Compra
Web Design for Developers 42,95 $US
Total 42,95 $US
Inicio
Preguntas
Noticias
Contacto

Orders
Products
Users

Su Catálogo de Pragmatic

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

34,95 $US
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

49,50 $US
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

42,95 $US
post /es/line_items?product_id=2
You are being redirected.
get http://localhost:3000/es
Carrito de la Compra
Web Design for Developers 85,90 $US
Total 85,90 $US
Inicio
Preguntas
Noticias
Contacto

Orders
Products
Users

Su Catálogo de Pragmatic

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

34,95 $US
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

49,50 $US
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

42,95 $US

Translate the model names to human names.

edit config/locales/es.yml
es:
 
  activerecord:
    models:
      order:       "pedido"
    attributes:
      order:
        address:   "Direcci&oacute;n"
        name:      "Nombre"
        email:     "E-mail"
        pay_type:  "Forma de pago"

Translate the errors to human names.

edit config/locales/es.yml
es:
 
  activerecord:
    errors:
      messages:
        inclusion: "no est&aacute; 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"

Show validation errors

get /es/orders/new
Por favor, introduzca sus datos
post /es/orders
Por favor, introduzca sus datos
5 errores han impedido que este pedido se guarde:
  • Nombre no puede quedar en blanco
  • Dirección no puede quedar en blanco
  • E-mail no puede quedar en blanco
  • Forma de pago no puede quedar en blanco
  • Forma de pago no está incluido en la lista

Replace translatable text with calls out to translation functions.

edit app/controllers/orders_controller.rb
  def create
    @order = Order.new(params[:order])
    @order.add_line_items_from_cart(current_cart)
 
    respond_to do |format|
      if @order.save
        Cart.destroy(session[:cart_id])
        session[:cart_id] = nil
        Notifier.order_received(@order).deliver
        format.html { redirect_to(store_url, :notice => 
          I18n.t('.thanks')) }
        format.xml  { render :xml => @order, :status => :created,
          :location => @order }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @order.errors,
          :status => :unprocessable_entity }
      end
    end
  end

Define some translations for the flash.

edit config/locales/en.yml
en:
 
  thanks:          "Thank you for your order"
edit config/locales/es.yml
es:
 
  thanks:          "Gracias por su pedido"

Place the order

get /es/orders/new
Por favor, introduzca sus datos
post /es/orders
You are being redirected.
get http://localhost:3000/es
Inicio
Preguntas
Noticias
Contacto

Orders
Products
Users

Gracias por su pedido

Su Catálogo de Pragmatic

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

34,95 $US
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

49,50 $US
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

42,95 $US

15.4 Task I4: Add a locale switcher.

</10 tests, 31 assertions, 0 failures, 0 errors/> expected but was
<"}">.

Traceback:
  /home/rubys/svn/rails4/Book/util/checkdepot.rb:260:in `block in <class:DepotTest>'

Add form for setting and showing the site based on the locale.

Use CSS to position the form.

edit public/stylesheets/depot.css
.locale {
        float:right;
        padding-top: 0.2em
}

When provided, save the locale in the session.

edit app/controllers/store_controller.rb
  def index
    if params[:set_locale]
      redirect_to store_path(:locale => params[:set_locale])
    else
      @products = Product.all
      @cart = current_cart
    end
  end

Try out the form

get /en
Home
Questions
News
Contact

Orders
Products
Users

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$42.95
post /en
You are being redirected.
get http://localhost:3000/es
Inicio
Preguntas
Noticias
Contacto

Orders
Products
Users

Su Catálogo de Pragmatic

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

34,95 $US
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

49,50 $US
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

42,95 $US
rake test
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_add_unique_products is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:10:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_should_get_new is already defined in SessionsControllerTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/sessions_controller_test.rb:4:in `<class:SessionsControllerTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/functional/sessions_controller_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/dsl_user_stories_test.rb:8: warning: already initialized constant DAVES_DETAILS
/home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/dsl_user_stories_test.rb:16: warning: already initialized constant MIKES_DETAILS
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_buying_a_product is already defined in UserStoriesTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:11:in `<class:UserStoriesTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/integration/user_stories_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
Errors running test:units, test:functionals, test:integration!

16 Deployment

git add .
git commit -a -m "save work"
Created commit 2f5bebf: save work
 95 files changed, 2277 insertions(+), 117 deletions(-)
 create mode 100644 app/controllers/admin_controller.rb
 create mode 100644 app/controllers/carts_controller.rb
 create mode 100644 app/controllers/line_items_controller.rb
 create mode 100644 app/controllers/orders_controller.rb
 create mode 100644 app/controllers/sessions_controller.rb
 create mode 100644 app/controllers/store_controller.rb
 create mode 100644 app/controllers/users_controller.rb
 create mode 100644 app/helpers/admin_helper.rb
 create mode 100644 app/helpers/carts_helper.rb
 create mode 100644 app/helpers/line_items_helper.rb
 create mode 100644 app/helpers/orders_helper.rb
 create mode 100644 app/helpers/sessions_helper.rb
 create mode 100644 app/helpers/store_helper.rb
 create mode 100644 app/helpers/users_helper.rb
 create mode 100644 app/mailers/notifier.rb
 create mode 100644 app/models/cart.rb
 create mode 100644 app/models/line_item.rb
 create mode 100644 app/models/order.rb
 create mode 100644 app/models/user.rb
 create mode 100644 app/views/admin/index.html.erb
 create mode 100644 app/views/carts/_cart.html.erb
 create mode 100644 app/views/carts/_form.html.erb
 create mode 100644 app/views/carts/edit.html.erb
 create mode 100644 app/views/carts/index.html.erb
 create mode 100644 app/views/carts/new.html.erb
 create mode 100644 app/views/carts/show.html.erb
 create mode 100644 app/views/line_items/_form.html.erb
 create mode 100644 app/views/line_items/_line_item.html.erb
 create mode 100644 app/views/line_items/_line_item.text.erb
 create mode 100644 app/views/line_items/create.js.rjs
 create mode 100644 app/views/line_items/edit.html.erb
 create mode 100644 app/views/line_items/index.html.erb
 create mode 100644 app/views/line_items/new.html.erb
 create mode 100644 app/views/line_items/show.html.erb
 create mode 100644 app/views/notifier/order_received.text.erb
 create mode 100644 app/views/notifier/order_shipped.html.erb
 create mode 100644 app/views/notifier/order_shipped.text.erb
 create mode 100644 app/views/orders/_form.html.erb
 create mode 100644 app/views/orders/edit.html.erb
 create mode 100644 app/views/orders/index.html.erb
 create mode 100644 app/views/orders/new.html.erb
 create mode 100644 app/views/orders/show.html.erb
 create mode 100644 app/views/products/who_bought.atom.builder
 create mode 100644 app/views/products/who_bought.html.erb
 create mode 100644 app/views/products/who_bought.xml.builder
 create mode 100644 app/views/sessions/create.html.erb
 create mode 100644 app/views/sessions/destroy.html.erb
 create mode 100644 app/views/sessions/new.html.erb
 create mode 100644 app/views/store/index.html.erb
 create mode 100644 app/views/users/_form.html.erb
 create mode 100644 app/views/users/edit.html.erb
 create mode 100644 app/views/users/index.html.erb
 create mode 100644 app/views/users/new.html.erb
 create mode 100644 app/views/users/show.html.erb
 create mode 100644 config/initializers/i18n.rb
 rewrite config/locales/en.yml (97%)
 create mode 100644 config/locales/es.yml
 rewrite config/routes.rb (88%)
 create mode 100644 db/migrate/20100301000002_create_carts.rb
 create mode 100644 db/migrate/20100301000003_create_line_items.rb
 create mode 100644 db/migrate/20100301000004_add_quantity_to_line_item.rb
 create mode 100644 db/migrate/20100301000005_combine_items_in_cart.rb
 create mode 100644 db/migrate/20100301000006_add_price_to_line_item.rb
 create mode 100644 db/migrate/20100301000007_create_orders.rb
 create mode 100644 db/migrate/20100301000008_add_order_id_to_line_item.rb
 create mode 100644 db/migrate/20100301000009_create_users.rb
 create mode 100644 script/load_orders.rb
 create mode 100644 test/fixtures/carts.yml
 create mode 100644 test/fixtures/line_items.yml
 create mode 100644 test/fixtures/orders.yml
 create mode 100644 test/fixtures/users.yml
 create mode 100644 test/functional/admin_controller_test.rb
 create mode 100644 test/functional/carts_controller_test.rb
 create mode 100644 test/functional/line_items_controller_test.rb
 create mode 100644 test/functional/notifier_test.rb
 create mode 100644 test/functional/orders_controller_test.rb
 create mode 100644 test/functional/sessions_controller_test.rb
 create mode 100644 test/functional/store_controller_test.rb
 create mode 100644 test/functional/users_controller_test.rb
 create mode 100644 test/integration/dsl_user_stories_test.rb
 create mode 100644 test/integration/user_stories_test.rb
 create mode 100644 test/unit/cart_test.rb
 create mode 100644 test/unit/helpers/admin_helper_test.rb
 create mode 100644 test/unit/helpers/carts_helper_test.rb
 create mode 100644 test/unit/helpers/line_items_helper_test.rb
 create mode 100644 test/unit/helpers/orders_helper_test.rb
 create mode 100644 test/unit/helpers/sessions_helper_test.rb
 create mode 100644 test/unit/helpers/store_helper_test.rb
 create mode 100644 test/unit/helpers/users_helper_test.rb
 create mode 100644 test/unit/line_item_test.rb
 create mode 100644 test/unit/order_test.rb
 create mode 100644 test/unit/user_test.rb
edit config/database.yml
# SQLite version 3.x
#   gem install sqlite3-ruby (not necessary on OS X Leopard)
development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000
 
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: sqlite3
  database: db/test.sqlite3
  pool: 5
  timeout: 5000
 
production:
  adapter: mysql
  encoding: utf8
  reconnect: false
  database: depot_production
  pool: 5
  username: username
  password: password
  host: localhost
edit Gemfile
# source 'http://rubygems.org'
 
gem 'rails', :path => "/home/rubys/git/rails" # '3.1.0.beta'
gem "arel", :path => "/home/rubys/git/arel"
 
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
 
gem 'sqlite3-ruby', :require => 'sqlite3'
group :production do
  gem 'mysql'
end
 
# Use unicorn as the web server
# gem 'unicorn'
 
# Deploy with Capistrano
gem 'capistrano'
 
# To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
# gem 'ruby-debug'
# gem 'ruby-debug19'
 
# Bundle the extra gems:
# gem 'bj'
# gem 'nokogiri'
# gem 'sqlite3-ruby', :require => 'sqlite3'
# gem 'aws-s3', :require => 'aws/s3'
 
gem 'will_paginate', '>= 3.0.pre'
 
# Bundle gems for the local environment. Make sure to
# put test-only gems in this group so their generators
# and rake tasks are available in development mode:
# group :development, :test do
#   gem 'webrat'
# end
bundle install
Using rake (0.8.7) 
Using abstract (1.0.0) 
Using activesupport (3.1.0.beta) from source at /home/rubys/git/rails 
Using builder (2.1.2) 
Using i18n (0.4.1) 
Using activemodel (3.1.0.beta) from source at /home/rubys/git/rails 
Using erubis (2.6.6) 
Using rack (1.2.1) 
Using rack-mount (0.6.13) 
Using rack-test (0.5.4) 
Using tzinfo (0.3.23) 
Using actionpack (3.1.0.beta) from source at /home/rubys/git/rails 
Using mime-types (1.16) 
Using polyglot (0.3.1) 
Using treetop (1.4.8) 
Using mail (2.2.5) 
Using actionmailer (3.1.0.beta) from source at /home/rubys/git/rails 
Using arel (1.0.1) from source at /home/rubys/git/arel 
Using activerecord (3.1.0.beta) from source at /home/rubys/git/rails 
Using activeresource (3.1.0.beta) from source at /home/rubys/git/rails 
Using bundler (1.0.0) 
Using highline (1.6.1) 
Using net-ssh (2.0.23) 
Using net-scp (1.0.3) 
Using net-sftp (2.0.5) 
Using net-ssh-gateway (1.0.1) 
Using capistrano (2.5.19) 
Using mysql (2.8.1) 
Using thor (0.14.0) 
Using railties (3.1.0.beta) from source at /home/rubys/git/rails 
Using rails (3.1.0.beta) from source at /home/rubys/git/rails 
Using sqlite3-ruby (1.3.1) 
Using will_paginate (3.0.pre2) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
*[32m
Your bundle was installed to `/home/rubys/.rvm/gems/ruby-1.9.3-r29181`*[0m
rake db:setup RAILS_ENV=production
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
depot_production already exists
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
-- create_table("carts", {:force=>true})
   -> 0.0400s
-- create_table("line_items", {:force=>true})
   -> 0.0176s
-- create_table("orders", {:force=>true})
   -> 0.0054s
-- create_table("products", {:force=>true})
   -> 0.0053s
-- create_table("users", {:force=>true})
   -> 0.0051s
-- initialize_schema_migrations_table()
   -> 0.0005s
-- assume_migrated_upto_version(20100301000009, "/home/rubys/svn/rails4/Book/util/work-193/depot/db/migrate")
   -> 0.0006s
bundle pack
Using rake (0.8.7) 
Using abstract (1.0.0) 
Using activesupport (3.1.0.beta) from source at /home/rubys/git/rails 
Using builder (2.1.2) 
Using i18n (0.4.1) 
Using activemodel (3.1.0.beta) from source at /home/rubys/git/rails 
Using erubis (2.6.6) 
Using rack (1.2.1) 
Using rack-mount (0.6.13) 
Using rack-test (0.5.4) 
Using tzinfo (0.3.23) 
Using actionpack (3.1.0.beta) from source at /home/rubys/git/rails 
Using mime-types (1.16) 
Using polyglot (0.3.1) 
Using treetop (1.4.8) 
Using mail (2.2.5) 
Using actionmailer (3.1.0.beta) from source at /home/rubys/git/rails 
Using arel (1.0.1) from source at /home/rubys/git/arel 
Using activerecord (3.1.0.beta) from source at /home/rubys/git/rails 
Using activeresource (3.1.0.beta) from source at /home/rubys/git/rails 
Using bundler (1.0.0) 
Using highline (1.6.1) 
Using net-ssh (2.0.23) 
Using net-scp (1.0.3) 
Using net-sftp (2.0.5) 
Using net-ssh-gateway (1.0.1) 
Using capistrano (2.5.19) 
Using mysql (2.8.1) 
Using thor (0.14.0) 
Using railties (3.1.0.beta) from source at /home/rubys/git/rails 
Using rails (3.1.0.beta) from source at /home/rubys/git/rails 
Using sqlite3-ruby (1.3.1) 
Using will_paginate (3.0.pre2) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
*[32m
Your bundle was installed to `/home/rubys/.rvm/gems/ruby-1.9.3-r29181`*[0m
Updating .gem files in vendor/cache
  * rake-0.8.7.gem
  * abstract-1.0.0.gem
  * activesupport at `/home/rubys/git/rails` will not be cached.
  * builder-2.1.2.gem
  * i18n-0.4.1.gem
  * activemodel at `/home/rubys/git/rails` will not be cached.
  * erubis-2.6.6.gem
  * rack-1.2.1.gem
  * rack-mount-0.6.13.gem
  * rack-test-0.5.4.gem
  * tzinfo-0.3.23.gem
  * actionpack at `/home/rubys/git/rails` will not be cached.
  * mime-types-1.16.gem
  * polyglot-0.3.1.gem
  * treetop-1.4.8.gem
  * mail-2.2.5.gem
  * actionmailer at `/home/rubys/git/rails` will not be cached.
  * arel at `/home/rubys/git/arel` will not be cached.
  * activerecord at `/home/rubys/git/rails` will not be cached.
  * activeresource at `/home/rubys/git/rails` will not be cached.
  * highline-1.6.1.gem
  * net-ssh-2.0.23.gem
  * net-scp-1.0.3.gem
  * net-sftp-2.0.5.gem
  * net-ssh-gateway-1.0.1.gem
  * capistrano-2.5.19.gem
  * mysql-2.8.1.gem
  * thor-0.14.0.gem
  * railties at `/home/rubys/git/rails` will not be cached.
  * rails at `/home/rubys/git/rails` will not be cached.
  * sqlite3-ruby-1.3.1.gem
  * will_paginate-3.0.pre2.gem
capify .
[add] writing './Capfile'
[add] writing './config/deploy.rb'
[done] capified!
edit config/deploy.rb
# be sure to change these
set :user, 'rubys'
set :domain, 'depot.pragprog.com'
set :application, 'depot'
 
# file paths
set :repository,  "#{user}@#{domain}:git/#{application}.git" 
set :deploy_to, "/home/#{user}/#{domain}" 
 
# distribute your applications across servers (the instructions below put them
# all on the same server, defined above as 'domain', adjust as necessary)
role :app, domain
role :web, domain
role :db, domain, :primary => true
 
# you might need to set this if you aren't seeing password prompts
# default_run_options[:pty] = true
 
# As Capistrano executes in a non-interactive mode and therefore doesn't cause
# any of your shell profile scripts to be run, the following might be needed
# if (for example) you have locally installed gems or applications.  Note:
# this needs to contain the full values for the variables set, not simply
# the deltas.
# default_environment['PATH']='<your paths>:/usr/local/bin:/usr/bin:/bin'
# default_environment['GEM_PATH']='<your paths>:/usr/lib/ruby/gems/1.8'
 
# miscellaneous options
set :deploy_via, :remote_cache
set :scm, 'git'
set :branch, 'master'
set :scm_verbose, true
set :use_sudo, false
 
# task which causes Passenger to initiate a restart
namespace :deploy do
  task :restart do
    run "touch #{current_path}/tmp/restart.txt" 
  end
 
  task :seed do
    run "cd #{current_path}; rake db:seed RAILS_ENV=production"
  end
end
 
# optional task to reconfigure databases
after "deploy:update_code", :bundle_install
desc "install the necessary prerequisites"
task :bundle_install, :roles => :app do
  run "cd #{release_path} && bundle install"
end
edit config/environments/production.rb
Depot::Application.configure do
  # Settings specified here will take precedence over those in config/environment.rb
 
  # The production environment is meant for finished, "live" apps.
  # Code is not reloaded between requests
  config.cache_classes = true
 
  # Full error reports are disabled and caching is turned on
  config.consider_all_requests_local       = false
  config.action_controller.perform_caching = true
 
  # Specifies the header that your server uses for sending files
  config.action_dispatch.x_sendfile_header = "X-Sendfile"
 
  # For nginx:
  # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
 
  # If you have no front-end server that supports something like X-Sendfile,
  # just comment this out and Rails will serve the files
 
  # See everything in the log (default is :info)
  # config.log_level = :debug
 
  # Use a different logger for distributed setups
  # config.logger = SyslogLogger.new
 
  # Use a different cache store in production
  # config.cache_store = :mem_cache_store
 
  # Disable Rails's static asset server
  # In production, Apache or nginx will already do this
  config.serve_static_assets = false
 
  # Enable serving of images, stylesheets, and javascripts from an asset server
  # config.action_controller.asset_host = "http://assets.example.com"
 
  # Disable delivery errors, bad email addresses will be ignored
  # config.action_mailer.raise_delivery_errors = false
 
  # Enable threaded mode
  # config.threadsafe!
 
  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
  # the I18n.default_locale when a translation can not be found)
  config.i18n.fallbacks = true
 
  # Send deprecation notices to registered listeners
  config.active_support.deprecation = :notify
 
  require 'active_support/core_ext/numeric/bytes'
  config.logger = Logger.new(paths.log.first, 2, 10.kilobytes)
end
echo "Depot::Application.configure { paths.log.first }" | IRBRC=tmp/irbrc rails console production
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Loading production environment (Rails 3.1.0.beta)
Switch to inspect mode.
>> Depot::Application.configure { paths.log.first }
=> "/home/rubys/svn/rails4/Book/util/work-193/depot/log/production.log"
>> 
git st
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#	modified:   Gemfile
#	modified:   Gemfile.lock
#	modified:   config/database.yml
#	modified:   config/environments/production.rb
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	Capfile
#	config/deploy.rb
#	vendor/cache/
no changes added to commit (use "git add" and/or "git commit -a")

17 Retrospective

edit doc/README_FOR_APP
= The Depot Online Store
 
This application implements an online store, with a catalog, cart, and orders.
 
It is divided into two main sections:
 
* The buyer's side of the application manages the catalog, cart, 
  and checkout. It is implementation spans in four models and associated
  controllers and views: Cart, LineItem, Order, and Product.  Additionally,
  there is a StoreController for the store front itself, and a
  SessionsController to manage sessions.
 
* Only administrators can access stuff in the seller's side
  (product maintenance and order fulfillment).  This is implemented by the
  LoginController, is enforced by the ApplicationController#authorize
  method, and assisted by the Users and Carts resources.
 
This code was produced as an example for the book {Agile Web Development with
Rails}[http://www.pragprog.com/titles/rails4/agile-web-development-with-rails-4th-edition]. It should not be 
run as a real online store.
 
=== Authors
 
 * Sam Ruby, IBM
 * Dave Thomas, The Pragmatic Programmers, LLC
 * David Heinemeier Hansson, 37signals
 
=== Warranty
 
This code is provided for educational purposes only, and comes with 
absolutely no warranty. It should not be used in live applications.
 
== Copyright
 
This code is Copyright (c) 2010 The Pragmatic Programmers, LLC.
 
It is released under the same license as Ruby.
rake doc:app
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
rm -r doc/app
invalid options: --line-numbers, --inline-source
(invalid options are ignored)
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
Parsing sources...
  4% [ 1/25]   doc/README_FOR_APP
  8% [ 2/25]   app/helpers/application_helper.rb
 12% [ 3/25]   app/helpers/store_helper.rb
 16% [ 4/25]   app/helpers/admin_helper.rb
 20% [ 5/25]   app/helpers/line_items_helper.rb
 24% [ 6/25]   app/helpers/orders_helper.rb
 28% [ 7/25]   app/helpers/users_helper.rb
 32% [ 8/25]   app/helpers/products_helper.rb
 36% [ 9/25]   app/helpers/sessions_helper.rb
 40% [10/25]   app/helpers/carts_helper.rb
 44% [11/25]   app/controllers/users_controller.rb
 48% [12/25]   app/controllers/store_controller.rb
 52% [13/25]   app/controllers/line_items_controller.rb
 56% [14/25]   app/controllers/sessions_controller.rb
 60% [15/25]   app/controllers/application_controller.rb
 64% [16/25]   app/controllers/admin_controller.rb
 68% [17/25]   app/controllers/products_controller.rb
 72% [18/25]   app/controllers/carts_controller.rb
 76% [19/25]   app/controllers/orders_controller.rb
 80% [20/25]   app/mailers/notifier.rb
 84% [21/25]   app/models/cart.rb
 88% [22/25]   app/models/user.rb
 92% [23/25]   app/models/product.rb
 96% [24/25]   app/models/line_item.rb
100% [25/25]   app/models/order.rb

    
Generating Darkfish...
 
 
Files:        25
Classes:      15 (    6 undocumented)
Constants:     1 (    0 undocumented)
Modules:       9 (    9 undocumented)
Methods:      60 (    7 undocumented)
 74.12% documented
 
Elapsed: 2.7s
rake stats
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
+----------------------+-------+-------+---------+---------+-----+-------+
| Name                 | Lines |   LOC | Classes | Methods | M/C | LOC/M |
+----------------------+-------+-------+---------+---------+-----+-------+
| Controllers          |   640 |   413 |       9 |      45 |   5 |     7 |
| Helpers              |    24 |    24 |       0 |       1 |   0 |    22 |
| Models               |   187 |   102 |       5 |      12 |   2 |     6 |
| Libraries            |     0 |     0 |       0 |       0 |   0 |     0 |
| Integration tests    |   201 |   138 |       2 |       9 |   4 |    13 |
| Functional tests     |   424 |   285 |       9 |       0 |   0 |     0 |
| Unit tests           |   163 |   123 |      13 |       2 |   0 |    59 |
+----------------------+-------+-------+---------+---------+-----+-------+
| Total                |  1639 |  1085 |      38 |      69 |   1 |    13 |
+----------------------+-------+-------+---------+---------+-----+-------+
  Code LOC: 539     Test LOC: 546     Code to Test Ratio: 1:1.0
 

18 Finding Your Way Around

rake db:version
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
Current version: 20100301000009
edit lib/tasks/db_schema_migrations.rake
namespace :db do
  desc "Prints the migrated versions"
  task :schema_migrations => :environment do
    puts ActiveRecord::Base.connection.select_values(
      'select version from schema_migrations order by version' )
  end
end
rake db:schema_migrations
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
20100301000001
20100301000002
20100301000003
20100301000004
20100301000005
20100301000006
20100301000007
20100301000008
20100301000009
ls log
development.log
production.log
server.log
test.log
find script -type f
script/rails
script/load_orders.rb
echo "puts $:" | IRBRC=tmp/irbrc rails console
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Loading development environment (Rails 3.1.0.beta)
Switch to inspect mode.
>> puts $:
/home/rubys/svn/rails4/Book/util/work-193/depot/lib
/home/rubys/svn/rails4/Book/util/work-193/depot/vendor
/home/rubys/svn/rails4/Book/util/work-193/depot/app/helpers
/home/rubys/svn/rails4/Book/util/work-193/depot/app/controllers
/home/rubys/svn/rails4/Book/util/work-193/depot/app/mailers
/home/rubys/svn/rails4/Book/util/work-193/depot/app/models
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/will_paginate-3.0.pre2/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/sqlite3-ruby-1.3.1/lib
/home/rubys/git/rails/lib
/home/rubys/git/rails/railties/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/thor-0.14.0/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/mysql-2.8.1/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/mysql-2.8.1/ext
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/capistrano-2.5.19/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/net-ssh-gateway-1.0.1/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/net-sftp-2.0.5/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/net-scp-1.0.3/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/net-ssh-2.0.23/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/highline-1.6.1/lib
/home/rubys/git/rails/activeresource/lib
/home/rubys/git/rails/activerecord/lib
/home/rubys/git/rails/actionmailer/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/mail-2.2.5/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/treetop-1.4.8/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/polyglot-0.3.1/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/mime-types-1.16/lib
/home/rubys/git/rails/actionpack/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/tzinfo-0.3.23/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rack-test-0.5.4/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rack-mount-0.6.13/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rack-1.2.1/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/erubis-2.6.6/lib
/home/rubys/git/rails/activemodel/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/i18n-0.4.1/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/builder-2.1.2/lib
/home/rubys/git/rails/activesupport/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/abstract-1.0.0/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib
/home/rubys/git/gorp/lib
/home/rubys/git/arel/lib
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/bundler-1.0.0/lib
/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/site_ruby/1.9.1
/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/site_ruby/1.9.1/i686-linux
/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/site_ruby
/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/vendor_ruby/1.9.1
/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/vendor_ruby/1.9.1/i686-linux
/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/vendor_ruby
/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1
/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/i686-linux
/home/rubys/git/rails/actionpack/lib/action_controller/vendor/html-scanner
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rack-mount-0.6.13/lib/rack/mount/vendor/multimap
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rack-mount-0.6.13/lib/rack/mount/vendor/regin
=> nil
>> 

19 Active Record

edit config/initializers/inflections.rb
# Be sure to restart your server when you modify this file.
 
# Add new inflection rules using the following format
# (all these examples are active by default):
# ActiveSupport::Inflector.inflections do |inflect|
#   inflect.plural /^(ox)$/i, '\1en'
#   inflect.singular /^(ox)en/i, '\1'
#   inflect.irregular 'person', 'people'
#   inflect.uncountable %w( fish sheep )
# end
 
ActiveSupport::Inflector.inflections do |inflect|
  inflect.irregular 'tax', 'taxes'
end

20.1 Testing Routes

</13 tests, 49 assertions, 0 failures, 0 errors/> expected but was
<"(in /home/rubys/svn/rails4/Book/util/work-193/depot)">.

Traceback:
  /home/rubys/svn/rails4/Book/util/checkdepot.rb:277:in `block in <class:DepotTest>'
edit test/unit/routing_test.rb
require 'test_helper'
require './config/routes.rb'
 
class RoutingTest < ActionController::TestCase
 
  def test_recognizes
    # Check the default index action gets generated
    assert_recognizes({"controller" => "store", "action" => "index"}, "/")
    
    # Check routing to an action
    assert_recognizes({"controller" => "products", "action" => "index"}, 
                      "/products")
    
    # And routing with a parameter
    assert_recognizes({ "controller" => "line_items", 
                        "action" => "create", 
                        "product_id" => "1" },
                        {:path => "/line_items", :method => :post},
                        {"product_id" => "1"})
  end
  
  def test_generates
    assert_generates("/", :controller => "store", :action => "index")
    assert_generates("/products", :controller => "products", :action => "index")
    assert_generates("/line_items", 
                     { :controller => "line_items", :action => "create", 
                       :product_id => "1"},
                     {:method => :post}, { :product_id => "1"})
  end
  
  def test_routing
    assert_routing("/", :controller => "store", :action => "index")
    assert_routing("/products", :controller => "products", :action => "index")
    assert_routing({:path => "/line_items", :method => :post},
                     { :controller => "line_items", :action => "create", 
                       :product_id => "1"},
                     {}, { :product_id => "1"})
  end
    
end
rake test:units
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
/home/rubys/git/rails/activesupport/lib/active_support/testing/declarative.rb:28:in `test': test_add_unique_products is already defined in CartTest (RuntimeError)
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:10:in `<class:CartTest>'
	from /home/rubys/svn/rails4/Book/util/work-193/depot/test/unit/cart_test.rb:3:in `<top (required)>'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `block in require'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:227:in `load_dependency'
	from /home/rubys/git/rails/activesupport/lib/active_support/dependencies.rb:239:in `require'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:79:in `block in non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `each'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:73:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:102:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:121:in `non_options'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:45:in `process_args'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/minitest/unit.rb:605:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:21:in `run'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:166:in `block (2 levels) in autorun'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:27:in `run_once'
	from /home/rubys/.rvm/rubies/ruby-1.9.3-r29181/lib/ruby/1.9.1/test/unit.rb:165:in `block in autorun'
rake aborted!
Command failed with status (1): [/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/...]

    
(See full trace by running task with --trace)

21.1 Views

edit app/views/products/index.xml.builder
xml.div(:class => "productlist") do
 
  xml.timestamp(Time.now)
  
  @products.each do |product|
    xml.product do
      xml.productname(product.title)
      xml.price(product.price, :currency => "USD")
    end
  end
end
edit app/controllers/products_controller.rb
  def index
    @products = Product.all
 
    respond_to do |format|
      format.html # index.html.erb
      format.xml  # index.xml.builder
    end
  end
curl --silent --user dave:secret http://localhost:3000/products.xml
<div class="productlist">
  <timestamp>2010-09-06 10:49:53 -0400</timestamp>
  <product>
    <productname>Debug It!</productname>
    <price currency="USD">34.95</price>
  </product>
  <product>
    <productname>Programming Ruby 1.9</productname>
    <price currency="USD">49.5</price>
  </product>
  <product>
    <productname>Web Design for Developers</productname>
    <price currency="USD">42.95</price>
  </product>
</div>
irb helpers/date.rb
Switch to inspect mode.
>> require 'active_support/all'
=> true
>> require 'action_view'
=> true
>> include ActionView::Helpers::DateHelper
=> Object
>> distance_of_time_in_words(Time.now, Time.local(2010, 12, 25))
=> "4 months"
>> distance_of_time_in_words(Time.now, Time.now + 33, false)
=> "1 minute"
>> distance_of_time_in_words(Time.now, Time.now + 33, true)
=> "half a minute"
>> time_ago_in_words(Time.local(2009, 12, 25))
=> "9 months"
 
irb helpers/number.rb
Switch to inspect mode.
>> require 'active_support/all'
=> true
>> require 'action_view'
=> true
>> include ActionView::Helpers::NumberHelper
=> Object
>> number_to_currency(123.45)
=> "$123.45"
>> number_to_currency(234.56, :unit => "CAN$", :precision => 0)
=> "CAN$235"
>> number_to_human_size(123_456)
=> "121 KB"
>> number_to_percentage(66.66666)
=> "66.667%"
>> number_to_percentage(66.66666, :precision => 1)
=> "66.7%"
>> number_to_phone(2125551212)
=> "212-555-1212"
>> number_to_phone(2125551212, :area_code => true, :delimiter => " ")
=> "(212) 555 1212"
>> number_with_delimiter(12345678)
=> "12,345,678"
>> number_with_delimiter(12345678, :delimiter => "_")
=> "12_345_678"
>> number_with_precision(50.0/3, :precision => 2)
=> "16.67"
 
pub depot_t

21.2 Form Helpers

/home/rubys/git/rails/bin/rails new views
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/thor-0.14.0/lib/thor/util.rb:219: Use RbConfig instead of obsolete and deprecated Config.
      create  
      create  README
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
      create  app
      create  app/helpers/application_helper.rb
      create  app/views/layouts/application.html.erb
      create  app/controllers/application_controller.rb
      create  app/mailers
      create  app/models
      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/test.rb
      create  config/environments/production.rb
      create  config/initializers
      create  config/initializers/mime_types.rb
      create  config/initializers/inflections.rb
      create  config/initializers/session_store.rb
      create  config/initializers/backtrace_silencers.rb
      create  config/initializers/secret_token.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/500.html
      create  public/robots.txt
      create  public/favicon.ico
      create  public/422.html
      create  public/404.html
      create  public/index.html
      create  public/images
      create  public/images/rails.png
      create  public/stylesheets
      create  public/stylesheets/.gitkeep
      create  public/javascripts
      create  public/javascripts/prototype.js
      create  public/javascripts/dragdrop.js
      create  public/javascripts/rails.js
      create  public/javascripts/effects.js
      create  public/javascripts/controls.js
      create  public/javascripts/application.js
      create  script
      create  script/rails
      create  test
      create  test/performance/browsing_test.rb
      create  test/test_helper.rb
      create  test/fixtures
      create  test/unit
      create  test/functional
      create  test/integration
      create  tmp
      create  tmp/sessions
      create  tmp/sockets
      create  tmp/cache
      create  tmp/pids
      create  vendor/plugins
      create  vendor/plugins/.gitkeep
bundle install
Using rake (0.8.7) 
Using abstract (1.0.0) 
Using activesupport (3.1.0.beta) from source at /home/rubys/git/rails 
Using builder (2.1.2) 
Using i18n (0.4.1) 
Using activemodel (3.1.0.beta) from source at /home/rubys/git/rails 
Using erubis (2.6.6) 
Using rack (1.2.1) 
Using rack-mount (0.6.13) 
Using rack-test (0.5.4) 
Using tzinfo (0.3.23) 
Using actionpack (3.1.0.beta) from source at /home/rubys/git/rails 
Using mime-types (1.16) 
Using polyglot (0.3.1) 
Using treetop (1.4.8) 
Using mail (2.2.5) 
Using actionmailer (3.1.0.beta) from source at /home/rubys/git/rails 
Using arel (1.0.1) from source at /home/rubys/git/arel 
Using activerecord (3.1.0.beta) from source at /home/rubys/git/rails 
Using activeresource (3.1.0.beta) from source at /home/rubys/git/rails 
Using bundler (1.0.0) 
Using thor (0.14.0) 
Using railties (3.1.0.beta) from source at /home/rubys/git/rails 
Using rails (3.1.0.beta) from source at /home/rubys/git/rails 
Using sqlite3-ruby (1.3.1) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
*[32m
Your bundle was installed to `/home/rubys/.rvm/gems/ruby-1.9.3-r29181`*[0m
rails generate model model input:string address:text color:string ketchup:boolean mustard:boolean mayonnaise:boolean start:date alarm:time
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      invoke  active_record
      create    db/migrate/20100906145009_create_models.rb
      create    app/models/model.rb
      invoke    test_unit
      create      test/unit/model_test.rb
      create      test/fixtures/models.yml
rails generate controller form input
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
      create  app/controllers/form_controller.rb
       route  get "form/input"
      invoke  erb
      create    app/views/form
      create    app/views/form/input.html.erb
      invoke  test_unit
      create    test/functional/form_controller_test.rb
      invoke  helper
      create    app/helpers/form_helper.rb
      invoke    test_unit
      create      test/unit/helpers/form_helper_test.rb
rake db:migrate
mv 20100906145009_create_models.rb 20100301000001_create_models.rb
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /home/rubys/svn/rails4/Book/util/work-193/views)
==  CreateModels: migrating ===================================================
-- create_table(:models)
   -> 0.0024s
==  CreateModels: migrated (0.0025s) ==========================================
 

Restart the server.

edit app/views/form/input.html.erb
<%= form_for :model do |form| %>
<p>
  <%= form.label :input %> <!-- <label id="helper.label"/> -->
  <%= form.text_field :input, :placeholder => 'Enter text here...' %> <!-- <label id="helper.text"/> -->
</p>
 
<p>
  <%= form.label :address, :style => 'float: left' %>
  <%= form.text_area :address, :rows => 3, :cols => 40 %> <!-- <label id="helper.textarea"/> -->
</p>
 
<p>
  <%= form.label :color %>:
  <%= form.radio_button :color, 'red' %> <!-- <label id="helper.radio"/> -->
  <%= form.label :red %>
  <%= form.radio_button :color, 'yellow' %>
  <%= form.label :yellow %>
  <%= form.radio_button :color, 'green' %>
  <%= form.label :green %>
</p>
 
<p>
  <%= form.label 'condiment' %>:
  <%= form.check_box :ketchup %> <!-- <label id="helper.checkbox"/> -->
  <%= form.label :ketchup %>
  <%= form.check_box :mustard %>
  <%= form.label :mustard %>
  <%= form.check_box :mayonnaise %>
  <%= form.label :mayonnaise %>
</p>
 
<p>
  <%= form.label :priority %>:
  <%= form.select :priority, (1..10) %> <!-- <label id="helper.select"/> -->
</p>
 
<p>
  <%= form.label :start %>:
  <%= form.date_select :start %> <!-- <label id="helper.date"/> -->
</p>
 
<p>
  <%= form.label :alarm %>:
  <%= form.time_select :alarm %> <!-- <label id="helper.time"/> -->
</p>
<% end %>
get /form/input

:

:

:

:

: :

pub /views

22 Active Resources

Restart the server.

/home/rubys/git/rails/bin/rails new depot_client
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/thor-0.14.0/lib/thor/util.rb:219: Use RbConfig instead of obsolete and deprecated Config.
      create  
      create  README
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
      create  app
      create  app/helpers/application_helper.rb
      create  app/views/layouts/application.html.erb
      create  app/controllers/application_controller.rb
      create  app/mailers
      create  app/models
      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/test.rb
      create  config/environments/production.rb
      create  config/initializers
      create  config/initializers/mime_types.rb
      create  config/initializers/inflections.rb
      create  config/initializers/session_store.rb
      create  config/initializers/backtrace_silencers.rb
      create  config/initializers/secret_token.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/500.html
      create  public/robots.txt
      create  public/favicon.ico
      create  public/422.html
      create  public/404.html
      create  public/index.html
      create  public/images
      create  public/images/rails.png
      create  public/stylesheets
      create  public/stylesheets/.gitkeep
      create  public/javascripts
      create  public/javascripts/prototype.js
      create  public/javascripts/dragdrop.js
      create  public/javascripts/rails.js
      create  public/javascripts/effects.js
      create  public/javascripts/controls.js
      create  public/javascripts/application.js
      create  script
      create  script/rails
      create  test
      create  test/performance/browsing_test.rb
      create  test/test_helper.rb
      create  test/fixtures
      create  test/unit
      create  test/functional
      create  test/integration
      create  tmp
      create  tmp/sessions
      create  tmp/sockets
      create  tmp/cache
      create  tmp/pids
      create  vendor/plugins
      create  vendor/plugins/.gitkeep
bundle install
Using rake (0.8.7) 
Using abstract (1.0.0) 
Using activesupport (3.1.0.beta) from source at /home/rubys/git/rails 
Using builder (2.1.2) 
Using i18n (0.4.1) 
Using activemodel (3.1.0.beta) from source at /home/rubys/git/rails 
Using erubis (2.6.6) 
Using rack (1.2.1) 
Using rack-mount (0.6.13) 
Using rack-test (0.5.4) 
Using tzinfo (0.3.23) 
Using actionpack (3.1.0.beta) from source at /home/rubys/git/rails 
Using mime-types (1.16) 
Using polyglot (0.3.1) 
Using treetop (1.4.8) 
Using mail (2.2.5) 
Using actionmailer (3.1.0.beta) from source at /home/rubys/git/rails 
Using arel (1.0.1) from source at /home/rubys/git/arel 
Using activerecord (3.1.0.beta) from source at /home/rubys/git/rails 
Using activeresource (3.1.0.beta) from source at /home/rubys/git/rails 
Using bundler (1.0.0) 
Using thor (0.14.0) 
Using railties (3.1.0.beta) from source at /home/rubys/git/rails 
Using rails (3.1.0.beta) from source at /home/rubys/git/rails 
Using sqlite3-ruby (1.3.1) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
*[32m
Your bundle was installed to `/home/rubys/.rvm/gems/ruby-1.9.3-r29181`*[0m
edit app/models/product.rb
class Product < ActiveResource::Base
  self.site = 'http://dave:secret@localhost:3000/'
end
echo "Product.find(2).title" | IRBRC=tmp/irbrc rails console
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Loading development environment (Rails 3.1.0.beta)
Switch to inspect mode.
>> Product.find(2).title
=> "Web Design for Developers"
>> 
edit app/controllers/line_items_controller.rb
  def create
    params[:line_item][:order_id] ||= params[:order_id]
    @cart = current_cart
    product = Product.find(params[:product_id])
    @line_item = @cart.add_product(product.id)
 
    respond_to do |format|
      if @line_item.save
        format.html { redirect_to(store_url) }
        format.js   { @current_item = @line_item }
        format.xml  { render :xml => @line_item,
          :status => :created, :location => @line_item }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @line_item.errors,
          :status => :unprocessable_entity }
      end
    end
  end
edit config/routes.rb
Depot::Application.routes.draw do
  get 'admin' => 'admin#index'
  controller :sessions do
    get  'login' => :new
    post 'login' => :create
    delete 'logout' => :destroy
  end
  scope '(:locale)' do
    resources :users
    resources :orders do
      resources :line_items
    end
 
    resources :line_items
    resources :carts
    resources :products do
      get :who_bought, :on => :member
    end
    root :to => 'store#index', :as => 'store'
  end
end
echo "Product.find(2).title" | IRBRC=tmp/irbrc rails console
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Loading development environment (Rails 3.1.0.beta)
Switch to inspect mode.
>> Product.find(2).title
=> "Web Design for Developers"
>> 
echo "p = Product.find(2)\\nputs p.price\\np.price-=5\\np.save" | IRBRC=tmp/irbrc rails console
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Loading development environment (Rails 3.1.0.beta)
Switch to inspect mode.
>> p = Product.find(2)
=> #<Product:0x9114aa0 @attributes={"created_at"=>2010-09-06 14:39:56 UTC, "description"=>"<p>\n       <em>Web Design for Developers</em> will show you how to make your\n       web-based application look professionally designed. We'll help you\n       learn how to pick the right colors and fonts, avoid costly interface\n       and accessibility mistakes -- your application will really come alive.\n       We'll also walk you through some common Photoshop and CSS techniques\n       and work through a web site redesign, taking a new design from concept\n       all the way to implementation.\n      </p>", "id"=>2, "image_url"=>"/images/wd4d.jpg", "price"=>#<BigDecimal:91154b4,'0.4295E2',18(18)>, "title"=>"Web Design for Developers", "updated_at"=>2010-09-06 14:39:56 UTC}, @prefix_options={}>
>> puts p.price
42.95
=> nil
>> p.price-=5
=> #<BigDecimal:9128294,'0.3795E2',18(36)>
>> p.save
=> true
>> 
get /
Home
Questions
News
Contact

Your Pragmatic Catalog

Debug

Debug It!

Professional programmers develop a knack of unerringly zeroing in on the root cause of a bug. They can do that because they've written a lot of buggy code and then gained experience fixing it. This book captures all this experience -- use it, and you'll find you write fewer bugs, and the ones you do write will become easier to hunt down.

$34.95
Ruby

Programming Ruby 1.9

Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox.

$49.50
Wd4d

Web Design for Developers

Web Design for Developers will show you how to make your web-based application look professionally designed. We'll help you learn how to pick the right colors and fonts, avoid costly interface and accessibility mistakes -- your application will really come alive. We'll also walk you through some common Photoshop and CSS techniques and work through a web site redesign, taking a new design from concept all the way to implementation.

$37.95
edit app/models/order.rb
class Order < ActiveResource::Base
  self.site = 'http://dave:secret@localhost:3000/'
end
echo "Order.find(1).name\\nOrder.find(1).line_items\\n" | IRBRC=tmp/irbrc rails console
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Loading development environment (Rails 3.1.0.beta)
Switch to inspect mode.
>> Order.find(1).name
=> "Dave Thomas"
>> Order.find(1).line_items
NoMethodError: undefined method `line_items' for #<Order:0x913b344>
	from /home/rubys/git/rails/activeresource/lib/active_resource/base.rb:1401:in `method_missing'
	from (irb):2
	from /home/rubys/git/rails/railties/lib/rails/commands/console.rb:44:in `start'
	from /home/rubys/git/rails/railties/lib/rails/commands/console.rb:8:in `start'
	from /home/rubys/git/rails/railties/lib/rails/commands.rb:23:in `<top (required)>'
	from script/rails:6:in `require'
	from script/rails:6:in `<main>'
>> 
edit app/models/line_item.rb
class LineItem < ActiveResource::Base
  self.site = 'http://dave:secret@localhost:3000/orders/:order_id'
end
get /orders/1/line_items.xml
<?xml version="1.0" encoding="UTF-8"?>
<line-items type="array">
  <line-item>
    <cart-id type="integer" nil="true"></cart-id>
    <created-at type="datetime">2010-09-06T14:42:56Z</created-at>
    <id type="integer">10</id>
    <order-id type="integer">1</order-id>
    <price type="decimal">49.5</price>
    <product-id type="integer">3</product-id>
    <quantity type="integer">1</quantity>
    <updated-at type="datetime">2010-09-06T14:43:35Z</updated-at>
  </line-item>
  <line-item>
    <cart-id type="integer" nil="true"></cart-id>
    <created-at type="datetime">2010-09-06T14:47:38Z</created-at>
    <id type="integer">11</id>
    <order-id type="integer">102</order-id>
    <price type="decimal">42.95</price>
    <product-id type="integer">2</product-id>
    <quantity type="integer">2</quantity>
    <updated-at type="datetime">2010-09-06T14:47:45Z</updated-at>
  </line-item>
</line-items>
echo "LineItem.find(:all, :params => {:order_id=>1})" | IRBRC=tmp/irbrc rails console
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Loading development environment (Rails 3.1.0.beta)
Switch to inspect mode.
>> LineItem.find(:all, :params => {:order_id=>1})
=> [#<LineItem:0x914b1b8 @attributes={"cart_id"=>nil, "created_at"=>2010-09-06 14:42:56 UTC, "id"=>10, "price"=>#<BigDecimal:914d350,'0.495E2',18(18)>, "product_id"=>3, "quantity"=>1, "updated_at"=>2010-09-06 14:43:35 UTC}, @prefix_options={:order_id=>1}>, #<LineItem:0x9149d04 @attributes={"cart_id"=>nil, "created_at"=>2010-09-06 14:47:38 UTC, "id"=>11, "price"=>#<BigDecimal:914bbe0,'0.4295E2',18(18)>, "product_id"=>2, "quantity"=>2, "updated_at"=>2010-09-06 14:47:45 UTC}, @prefix_options={:order_id=>1}>]
>> 
echo "li = LineItem.find(:all, :params => {:order_id=>1}).first\\nputs li.price\\nli.price*=0.8\\nli.save\\nli2 = LineItem.new(:order_id=>1, :product_id=>2, :quantity=>1, :price=>0.0)\\nli2.save" | IRBRC=tmp/irbrc rails console
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Loading development environment (Rails 3.1.0.beta)
Switch to inspect mode.
>> li = LineItem.find(:all, :params => {:order_id=>1}).first
=> #<LineItem:0x915026c @attributes={"cart_id"=>nil, "created_at"=>2010-09-06 14:42:56 UTC, "id"=>10, "price"=>#<BigDecimal:9153480,'0.495E2',18(18)>, "product_id"=>3, "quantity"=>1, "updated_at"=>2010-09-06 14:43:35 UTC}, @prefix_options={:order_id=>1}>
>> puts li.price
49.5
=> nil
>> li.price*=0.8
=> 39.6
>> li.save
=> true
>> li2 = LineItem.new(:order_id=>1, :product_id=>2, :quantity=>1, :price=>0.0)
=> #<LineItem:0x8e2b58c @attributes={"product_id"=>2, "quantity"=>1, "price"=>0.0}, @prefix_options={:order_id=>1}>
>> li2.save
ActiveResource::ResourceNotFound: Failed.  Response code = 404.  Response message = Not Found .
	from /home/rubys/git/rails/activeresource/lib/active_resource/connection.rb:135:in `handle_response'
	from /home/rubys/git/rails/activeresource/lib/active_resource/connection.rb:114:in `request'
	from /home/rubys/git/rails/activeresource/lib/active_resource/connection.rb:97:in `block in post'
	from /home/rubys/git/rails/activeresource/lib/active_resource/connection.rb:217:in `with_auth'
	from /home/rubys/git/rails/activeresource/lib/active_resource/connection.rb:97:in `post'
	from /home/rubys/git/rails/activeresource/lib/active_resource/base.rb:1314:in `create'
	from /home/rubys/git/rails/activeresource/lib/active_resource/observing.rb:11:in `create_with_notifications'
	from /home/rubys/git/rails/activeresource/lib/active_resource/base.rb:1117:in `save'
	from /home/rubys/git/rails/activeresource/lib/active_resource/validations.rb:79:in `save_with_validation'
	from /home/rubys/git/rails/activeresource/lib/active_resource/observing.rb:11:in `save_with_notifications'
	from (irb):6
	from /home/rubys/git/rails/railties/lib/rails/commands/console.rb:44:in `start'
	from /home/rubys/git/rails/railties/lib/rails/commands/console.rb:8:in `start'
	from /home/rubys/git/rails/railties/lib/rails/commands.rb:23:in `<top (required)>'
	from script/rails:6:in `require'
	from script/rails:6:in `<main>'
>> 
echo "li = LineItem.new(:order_id=>1, :product_id=>2, :quantity=>1)\\nli2.save" | IRBRC=tmp/irbrc rails console
/home/rubys/git/rails/railties/lib/rails/engine.rb:460: Use RbConfig instead of obsolete and deprecated Config.
Loading development environment (Rails 3.1.0.beta)
Switch to inspect mode.
>> li = LineItem.new(:order_id=>1, :product_id=>2, :quantity=>1)
=> #<LineItem:0x8f34564 @attributes={"product_id"=>2, "quantity"=>1}, @prefix_options={:order_id=>1}>
>> li2.save
NameError: undefined local variable or method `li2' for main:Object
	from (irb):2
	from /home/rubys/git/rails/railties/lib/rails/commands/console.rb:44:in `start'
	from /home/rubys/git/rails/railties/lib/rails/commands/console.rb:8:in `start'
	from /home/rubys/git/rails/railties/lib/rails/commands.rb:23:in `<top (required)>'
	from script/rails:6:in `require'
	from script/rails:6:in `<main>'
>> 
pub /depot_client

25.2 rake

implement a custom rake task

edit lib/tasks/db_backup.rake
namespace :db do
 
  desc "Backup the production database"
  task :backup => :environment do
    backup_dir  = ENV['DIR'] || File.join(Rails.root, 'db', 'backup')
 
    source = File.join(Rails.root, 'db', "production.db")
    dest   = File.join(backup_dir, "production.backup")
 
    makedirs backup_dir
    sh "sqlite3 #{source} .dump > #{dest}"
  end
 
end
rake db:backup
/home/rubys/.rvm/gems/ruby-1.9.3-r29181/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
mkdir -p /home/rubys/svn/rails4/Book/util/work-193/depot/db/backup
sqlite3 /home/rubys/svn/rails4/Book/util/work-193/depot/db/production.db .dump > /home/rubys/svn/rails4/Book/util/work-193/depot/db/backup/production.backup
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
pub depot_u

Environment

Mon, 06 Sep 2010 14:51:47 GMT
/home/rubys/.rvm/rubies/ruby-1.9.3-r29181/bin/ruby -v
ruby 1.9.3dev (2010-09-04 trunk 29181) [i686-linux]
gem -v
1.3.7

Todos