Agile Web Development with Rails, Edition 4
Agile Web Development with Rails, Edition 4
12.2 Iteration G2: Atom Feeds
11.5 Iteration F5: Testing AJAX changes
12.1 Iteration G1: Capturing an Order
rails generate scaffold Order name:string address:text email:string pay_type:string
invoke active_record
create db/migrate/20100606143729_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/20100606143729_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
invoke active_record
create db/migrate/20100606143733_add_order_id_to_line_item.rb
rake db:migrate
mv 20100606143729_create_orders.rb 20100301000006_create_orders.rb
mv 20100606143733_add_order_id_to_line_item.rb 20100301000007_add_order_id_to_line_item.rb
(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.0010s
== AddOrderIdToLineItem: migrated (0.0011s) ==================================
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, "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 find_or_create_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.text_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(find_or_create_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
Pragmatic Bookshelf
post /orders
Pragmatic Bookshelf
sqlite3> select * from orders
sqlite3> select * from line_items
id = 10
product_id = 3
cart_id = 3
created_at = 2010-06-06 14:36:49.301327
updated_at = 2010-06-06 14:36:49.301327
quantity = 1
order_id =
get /orders/new
Pragmatic Bookshelf
post /orders
order[name] => Dave Thomas
order[address] => 123 Main St
order[email] => customer@example.com
order[pay_type] => Check
You are being
redirected .
get http://localhost:3000/
Pragmatic Bookshelf
Thank you for your order.
Your Pragmatic Catalog
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.
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.
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.
sqlite3> select * from orders
id = 1
name = Dave Thomas
address = 123 Main St
email = customer@example.com
pay_type = Check
created_at = 2010-06-06 14:37:41.822634
updated_at = 2010-06-06 14:37:41.822634
sqlite3> select * from line_items
id = 10
product_id = 3
cart_id =
created_at = 2010-06-06 14:36:49.301327
updated_at = 2010-06-06 14:37:41.838448
quantity = 1
order_id = 1
edit app/views/line_items/create.js.rjs
page.select("div#notice").each { |div| div.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
11.5 Iteration F5: Testing AJAX changes