Agile Web Development with Rails, Edition 4

Agile Web Development with Rails, Edition 4

6.2 Iteration A2: Making Prettier Listings 2 Instant Gratification

6.1 Iteration A1: Creating the Products Maintenance Application

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.

bundle exec /home/rubys/git/rails/bin/rails new depot --skip-bundle --dev
      create  
      create  README
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
      create  app
      create  app/controllers/application_controller.rb
      create  app/helpers/application_helper.rb
      create  app/mailers
      create  app/models
      create  app/views/layouts/application.html.erb
      create  config
      create  config/routes.rb
      create  config/application.rb
      create  config/environment.rb
      create  config/environments
      create  config/environments/development.rb
      create  config/environments/production.rb
      create  config/environments/test.rb
      create  config/initializers
      create  config/initializers/backtrace_silencers.rb
      create  config/initializers/inflections.rb
      create  config/initializers/mime_types.rb
      create  config/initializers/secret_token.rb
      create  config/initializers/session_store.rb
      create  config/locales
      create  config/locales/en.yml
      create  config/boot.rb
      create  config/database.yml
      create  db
      create  db/seeds.rb
      create  doc
      create  doc/README_FOR_APP
      create  lib
      create  lib/tasks
      create  lib/tasks/.gitkeep
      create  log
      create  log/server.log
      create  log/production.log
      create  log/development.log
      create  log/test.log
      create  public
      create  public/404.html
      create  public/422.html
      create  public/500.html
      create  public/favicon.ico
      create  public/index.html
      create  public/robots.txt
      create  public/images
      create  public/images/rails.png
      create  public/stylesheets
      create  public/stylesheets/.gitkeep
      create  public/javascripts
      create  public/javascripts/application.js
      create  public/javascripts/controls.js
      create  public/javascripts/dragdrop.js
      create  public/javascripts/effects.js
      create  public/javascripts/prototype.js
      create  public/javascripts/rails.js
      create  script
      create  script/rails
      create  test
      create  test/fixtures
      create  test/functional
      create  test/integration
      create  test/performance/browsing_test.rb
      create  test/test_helper.rb
      create  test/unit
      create  tmp
      create  tmp/sessions
      create  tmp/sockets
      create  tmp/cache
      create  tmp/pids
      create  vendor/plugins
      create  vendor/plugins/.gitkeep
bundle install
Using rake (0.9.2.2) 
Using abstract (1.0.0) 
Using activesupport (3.0.15) 
Using builder (2.1.2) 
Using i18n (0.5.0) 
Using activemodel (3.0.15) 
Using erubis (2.6.6) 
Using rack (1.2.5) 
Using rack-mount (0.6.14) 
Using rack-test (0.5.7) 
Using tzinfo (0.3.33) 
Using actionpack (3.0.15) 
Using mime-types (1.19) 
Using polyglot (0.3.3) 
Using treetop (1.4.10) 
Using mail (2.2.19) 
Using actionmailer (3.0.15) 
Using arel (2.0.10) 
Using activerecord (3.0.15) 
Using activeresource (3.0.15) 
Using bundler (1.1.3) 
Using json (1.7.3) 
Using rdoc (3.12) 
Using thor (0.14.6) 
Using railties (3.0.15) 
Using rails (3.0.15) 
Using sqlite3 (1.3.6) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.

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/

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
      invoke  active_record
      create    db/migrate/20120629162929_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 %>

Add precision and scale to the price

edit db/migrate/20120629162929_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 20120629162929_create_products.rb 20110711000001_create_products.rb
==  CreateProducts: migrating =================================================
-- create_table(:products)
   -> 0.0019s
==  CreateProducts: migrated (0.0020s) ========================================
 

Restart the server.

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: CoffeeScript

Description: <p> CoffeeScript is JavaScript done right. It provides all of JavaScript's functionality wrapped in a cleaner, more succinct syntax. In the first book on this exciting new language, CoffeeScript guru Trevor Burnham shows you how to hold onto all the power and flexibility of JavaScript while writing clearer, cleaner, and safer code. </p>

Image url: /images/cs.jpg

Price: 29.0

Edit | Back

Verify that the product has been added

get /products

Listing products

Title Description Image url Price
CoffeeScript <p> CoffeeScript is JavaScript done right. It provides all of JavaScript's functionality wrapped in a cleaner, more succinct syntax. In the first book on this exciting new language, CoffeeScript guru Trevor Burnham shows you how to hold onto all the power and flexibility of JavaScript while writing clearer, cleaner, and safer code. </p> /images/cs.jpg 29.0 Show Edit Destroy

New Product

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

rake test
Loaded suite /home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rake-0.9.2.2/lib/rake/rake_test_loader
Started
.
Finished in 0.212602 seconds.
 
1 tests, 1 assertions, 0 failures, 0 errors
Loaded suite /home/rubys/.rvm/gems/ruby-1.8.7-p352/gems/rake-0.9.2.2/lib/rake/rake_test_loader
Started
.......
Finished in 0.348707 seconds.
 
7 tests, 10 assertions, 0 failures, 0 errors

6.2 Iteration A2: Making Prettier Listings 2 Instant Gratification