Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial import

  • Loading branch information...
commit 5e5985614aa589049ab45cf014da5741a1d05614 0 parents
Andy Waite authored
Showing with 4,617 additions and 0 deletions.
  1. +11 −0 Capfile
  2. +53 −0 Gemfile
  3. +261 −0 README.rdoc
  4. +7 −0 Rakefile
  5. BIN  app/assets/images/cs.jpg
  6. BIN  app/assets/images/logo.png
  7. BIN  app/assets/images/rails.png
  8. BIN  app/assets/images/rtp.jpg
  9. BIN  app/assets/images/ruby.jpg
  10. +3 −0  app/assets/javascripts/admin.js.coffee
  11. +25 −0 app/assets/javascripts/application.js
  12. +3 −0  app/assets/javascripts/carts.js.coffee
  13. +3 −0  app/assets/javascripts/line_items.js.coffee
  14. +3 −0  app/assets/javascripts/orders.js.coffee
  15. +3 −0  app/assets/javascripts/products.js.coffee
  16. +3 −0  app/assets/javascripts/sessions.js.coffee
  17. +9 −0 app/assets/javascripts/store.js.coffee
  18. +3 −0  app/assets/javascripts/users.js.coffee
  19. +3 −0  app/assets/stylesheets/admin.css.scss
  20. +135 −0 app/assets/stylesheets/application.css.scss
  21. +20 −0 app/assets/stylesheets/carts.css.scss
  22. +3 −0  app/assets/stylesheets/line_items.css.scss
  23. +3 −0  app/assets/stylesheets/orders.css.scss
  24. +53 −0 app/assets/stylesheets/products.css.scss
  25. +56 −0 app/assets/stylesheets/scaffolds.css.scss
  26. +3 −0  app/assets/stylesheets/sessions.css.scss
  27. +57 −0 app/assets/stylesheets/store.css.scss
  28. +3 −0  app/assets/stylesheets/users.css.scss
  29. +13 −0 app/controllers/admin_controller.rb
  30. +57 −0 app/controllers/application_controller.rb
  31. +99 −0 app/controllers/carts_controller.rb
  32. +106 −0 app/controllers/line_items_controller.rb
  33. +108 −0 app/controllers/orders_controller.rb
  34. +107 −0 app/controllers/products_controller.rb
  35. +28 −0 app/controllers/sessions_controller.rb
  36. +23 −0 app/controllers/store_controller.rb
  37. +101 −0 app/controllers/users_controller.rb
  38. +10 −0 app/helpers/admin_helper.rb
  39. +16 −0 app/helpers/application_helper.rb
  40. +10 −0 app/helpers/carts_helper.rb
  41. +10 −0 app/helpers/line_items_helper.rb
  42. +10 −0 app/helpers/orders_helper.rb
  43. +10 −0 app/helpers/products_helper.rb
  44. +10 −0 app/helpers/sessions_helper.rb
  45. +10 −0 app/helpers/store_helper.rb
  46. +10 −0 app/helpers/users_helper.rb
  47. 0  app/mailers/.gitkeep
  48. +33 −0 app/mailers/order_notifier.rb
  49. 0  app/models/.gitkeep
  50. +26 −0 app/models/cart.rb
  51. +17 −0 app/models/line_item.rb
  52. +21 −0 app/models/order.rb
  53. +42 −0 app/models/product.rb
  54. +21 −0 app/models/user.rb
  55. +33 −0 app/store.rb
  56. +4 −0 app/views/admin/index.html.erb
  57. +20 −0 app/views/carts/_cart.html.erb
  58. +17 −0 app/views/carts/_form.html.erb
  59. +6 −0 app/views/carts/edit.html.erb
  60. +21 −0 app/views/carts/index.html.erb
  61. +5 −0 app/views/carts/new.html.erb
  62. +7 −0 app/views/carts/show.html.erb
  63. +58 −0 app/views/layouts/application.html.erb
  64. +25 −0 app/views/line_items/_form.html.erb
  65. +9 −0 app/views/line_items/_line_item.html.erb
  66. +3 −0  app/views/line_items/_line_item.text.erb
  67. +10 −0 app/views/line_items/create.js.erb
  68. +6 −0 app/views/line_items/edit.html.erb
  69. +25 −0 app/views/line_items/index.html.erb
  70. +5 −0 app/views/line_items/new.html.erb
  71. +15 −0 app/views/line_items/show.html.erb
  72. +9 −0 app/views/order_notifier/received.text.erb
  73. +9 −0 app/views/order_notifier/shipped.html.erb
  74. +3 −0  app/views/order_notifier/shipped.text.erb
  75. +49 −0 app/views/orders/_form.html.erb
  76. +6 −0 app/views/orders/edit.html.erb
  77. +33 −0 app/views/orders/index.html.erb
  78. +8 −0 app/views/orders/new.html.erb
  79. +25 −0 app/views/orders/show.html.erb
  80. +36 −0 app/views/products/_form.html.erb
  81. +6 −0 app/views/products/edit.html.erb
  82. +32 −0 app/views/products/index.html.erb
  83. +11 −0 app/views/products/index.xml.builder
  84. +5 −0 app/views/products/new.html.erb
  85. +25 −0 app/views/products/show.html.erb
  86. +41 −0 app/views/products/who_bought.atom.builder
  87. +9 −0 app/views/products/who_bought.html.erb
  88. +8 −0 app/views/products/who_bought.xml.builder
  89. +2 −0  app/views/sessions/create.html.erb
  90. +2 −0  app/views/sessions/destroy.html.erb
  91. +25 −0 app/views/sessions/new.html.erb
  92. +14 −0 app/views/store/index.html.haml
  93. +41 −0 app/views/users/_form.html.erb
  94. +6 −0 app/views/users/edit.html.erb
  95. +29 −0 app/views/users/index.html.erb
  96. +5 −0 app/views/users/new.html.erb
  97. +15 −0 app/views/users/show.html.erb
  98. +4 −0 config.ru
  99. +67 −0 config/application.rb
  100. +14 −0 config/boot.rb
  101. +31 −0 config/database.yml
  102. +65 −0 config/deploy.rb
  103. +13 −0 config/environment.rb
  104. +60 −0 config/environments/development.rb
  105. +78 −0 config/environments/production.rb
  106. +45 −0 config/environments/test.rb
  107. +15 −0 config/initializers/backtrace_silencers.rb
  108. +15 −0 config/initializers/i18n.rb
  109. +27 −0 config/initializers/inflections.rb
  110. +13 −0 config/initializers/mime_types.rb
  111. +15 −0 config/initializers/secret_token.rb
  112. +16 −0 config/initializers/session_store.rb
  113. +22 −0 config/initializers/wrap_parameters.rb
  114. +73 −0 config/locales/en.yml
  115. +94 −0 config/locales/es.yml
  116. +31 −0 config/routes.rb
  117. +3 −0  db/backup/production.backup
  118. +20 −0 db/migrate/20110711000001_create_products.rb
  119. +16 −0 db/migrate/20110711000002_create_carts.rb
  120. +18 −0 db/migrate/20110711000003_create_line_items.rb
  121. +14 −0 db/migrate/20110711000004_add_quantity_to_line_items.rb
  122. +42 −0 db/migrate/20110711000005_combine_items_in_cart.rb
  123. +17 −0 db/migrate/20110711000006_add_price_to_line_item.rb
  124. +20 −0 db/migrate/20110711000007_create_orders.rb
  125. +14 −0 db/migrate/20110711000008_add_order_id_to_line_item.rb
  126. +18 −0 db/migrate/20110711000009_create_users.rb
  127. 0  db/production.db
  128. +64 −0 db/schema.rb
  129. +45 −0 db/seeds.rb
  130. +37 −0 doc/README_FOR_APP
  131. 0  lib/assets/.gitkeep
  132. 0  lib/tasks/.gitkeep
  133. +14 −0 lib/tasks/db_backup.rake
  134. +7 −0 lib/tasks/db_schema_migrations.rake
  135. +34 −0 public/404.html
  136. +34 −0 public/422.html
  137. +33 −0 public/500.html
  138. 0  public/favicon.ico
  139. +5 −0 public/robots.txt
  140. +18 −0 script/creditcard.rb
  141. +14 −0 script/load_orders.rb
  142. +6 −0 script/rails
  143. +10 −0 store.ru
  144. 0  test/fixtures/.gitkeep
  145. +11 −0 test/fixtures/carts.yml
  146. +12 −0 test/fixtures/line_items.yml
  147. +20 −0 test/fixtures/orders.yml
  148. +25 −0 test/fixtures/products.yml
  149. +10 −0 test/fixtures/users.yml
  150. 0  test/functional/.gitkeep
  151. +17 −0 test/functional/admin_controller_test.rb
  152. +58 −0 test/functional/carts_controller_test.rb
  153. +68 −0 test/functional/line_items_controller_test.rb
  154. +29 −0 test/functional/order_notifier_test.rb
  155. +67 −0 test/functional/orders_controller_test.rb
  156. +77 −0 test/functional/products_controller_test.rb
  157. +35 −0 test/functional/sessions_controller_test.rb
  158. +26 −0 test/functional/store_controller_test.rb
  159. +65 −0 test/functional/users_controller_test.rb
  160. 0  test/integration/.gitkeep
  161. +128 −0 test/integration/dsl_user_stories_test.rb
  162. +67 −0 test/integration/user_stories_test.rb
  163. +20 −0 test/performance/browsing_test.rb
  164. +33 −0 test/test_helper.rb
  165. 0  test/unit/.gitkeep
  166. +32 −0 test/unit/cart_test.rb
  167. +12 −0 test/unit/helpers/admin_helper_test.rb
  168. +12 −0 test/unit/helpers/carts_helper_test.rb
  169. +12 −0 test/unit/helpers/line_items_helper_test.rb
  170. +12 −0 test/unit/helpers/orders_helper_test.rb
  171. +12 −0 test/unit/helpers/products_helper_test.rb
  172. +12 −0 test/unit/helpers/sessions_helper_test.rb
  173. +12 −0 test/unit/helpers/store_helper_test.rb
  174. +12 −0 test/unit/helpers/users_helper_test.rb
  175. +15 −0 test/unit/line_item_test.rb
  176. +15 −0 test/unit/order_test.rb
  177. +81 −0 test/unit/product_test.rb
  178. +50 −0 test/unit/routing_test.rb
  179. +15 −0 test/unit/user_test.rb
  180. 0  vendor/assets/javascripts/.gitkeep
  181. 0  vendor/assets/stylesheets/.gitkeep
  182. BIN  vendor/cache/i18n-0.6.0.gem
  183. BIN  vendor/cache/multi_json-1.0.4.gem
  184. BIN  vendor/cache/rake-0.9.2.2.gem
11 Capfile
@@ -0,0 +1,11 @@
+load 'deploy' if respond_to?(:namespace) # cap2 differentiator
+
+# Uncomment if you are using Rails' asset pipeline
+#START_HIGHLIGHT
+load 'deploy/assets'
+#END_HIGHLIGHT
+
+Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].
+ each { |plugin| load(plugin) }
+
+load 'config/deploy' # remove this line to skip loading any of the default tasks
53 Gemfile
@@ -0,0 +1,53 @@
+source 'https://rubygems.org'
+
+gem 'rails', '3.2.0'
+
+# Bundle edge Rails instead:
+# gem 'rails', :git => 'git://github.com/rails/rails.git'
+
+gem 'sqlite3'
+group :production do
+ gem 'mysql2'
+end
+
+
+# Gems used only for assets and not required
+# in production environments by default.
+group :assets do
+ gem 'sass-rails', '~> 3.2.3'
+ gem 'coffee-rails', '~> 3.2.1'
+
+ # See https://github.com/sstephenson/execjs#readme for more supported runtimes
+ # gem 'therubyracer'
+
+ gem 'uglifier', '>= 1.0.3'
+end
+
+gem 'jquery-rails'
+
+# To use ActiveModel has_secure_password
+gem 'bcrypt-ruby', '~> 3.0.0'
+
+# To use Jbuilder templates for JSON
+# gem 'jbuilder'
+
+# Use unicorn as the web server
+# gem 'unicorn'
+
+# Deploy with Capistrano
+gem 'capistrano'
+
+# To use debugger
+# gem 'ruby-debug19', :require => 'ruby-debug'
+
+gem 'will_paginate', '~> 3.0'
+
+#START:plugins
+#START_HIGHLIGHT
+gem 'activemerchant'
+#START_HIGHLIGHT
+gem 'haml', '~> 3.1.1'
+#END_HIGHLIGHT
+#END_HIGHLIGHT
+#END:plugins
+
261 README.rdoc
@@ -0,0 +1,261 @@
+== Welcome to Rails
+
+Rails is a web-application framework that includes everything needed to create
+database-backed web applications according to the Model-View-Control pattern.
+
+This pattern splits the view (also called the presentation) into "dumb"
+templates that are primarily responsible for inserting pre-built data in between
+HTML tags. The model contains the "smart" domain objects (such as Account,
+Product, Person, Post) that holds all the business logic and knows how to
+persist themselves to a database. The controller handles the incoming requests
+(such as Save New Account, Update Product, Show Post) by manipulating the model
+and directing data to the view.
+
+In Rails, the model is handled by what's called an object-relational mapping
+layer entitled Active Record. This layer allows you to present the data from
+database rows as objects and embellish these data objects with business logic
+methods. You can read more about Active Record in
+link:files/vendor/rails/activerecord/README.html.
+
+The controller and view are handled by the Action Pack, which handles both
+layers by its two parts: Action View and Action Controller. These two layers
+are bundled in a single package due to their heavy interdependence. This is
+unlike the relationship between the Active Record and Action Pack that is much
+more separate. Each of these packages can be used independently outside of
+Rails. You can read more about Action Pack in
+link:files/vendor/rails/actionpack/README.html.
+
+
+== Getting Started
+
+1. At the command prompt, create a new Rails application:
+ <tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name)
+
+2. Change directory to <tt>myapp</tt> and start the web server:
+ <tt>cd myapp; rails server</tt> (run with --help for options)
+
+3. Go to http://localhost:3000/ and you'll see:
+ "Welcome aboard: You're riding Ruby on Rails!"
+
+4. Follow the guidelines to start developing your application. You can find
+the following resources handy:
+
+* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html
+* Ruby on Rails Tutorial Book: http://www.railstutorial.org/
+
+
+== Debugging Rails
+
+Sometimes your application goes wrong. Fortunately there are a lot of tools that
+will help you debug it and get it back on the rails.
+
+First area to check is the application log files. Have "tail -f" commands
+running on the server.log and development.log. Rails will automatically display
+debugging and runtime information to these files. Debugging info will also be
+shown in the browser on requests from 127.0.0.1.
+
+You can also log your own messages directly into the log file from your code
+using the Ruby logger class from inside your controllers. Example:
+
+ class WeblogController < ActionController::Base
+ def destroy
+ @weblog = Weblog.find(params[:id])
+ @weblog.destroy
+ logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
+ end
+ end
+
+The result will be a message in your log file along the lines of:
+
+ Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1!
+
+More information on how to use the logger is at http://www.ruby-doc.org/core/
+
+Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are
+several books available online as well:
+
+* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe)
+* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
+
+These two books will bring you up to speed on the Ruby language and also on
+programming in general.
+
+
+== Debugger
+
+Debugger support is available through the debugger command when you start your
+Mongrel or WEBrick server with --debugger. This means that you can break out of
+execution at any point in the code, investigate and change the model, and then,
+resume execution! You need to install ruby-debug to run the server in debugging
+mode. With gems, use <tt>sudo gem install ruby-debug</tt>. Example:
+
+ class WeblogController < ActionController::Base
+ def index
+ @posts = Post.all
+ debugger
+ end
+ end
+
+So the controller will accept the action, run the first line, then present you
+with a IRB prompt in the server window. Here you can do things like:
+
+ >> @posts.inspect
+ => "[#<Post:0x14a6be8
+ @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>,
+ #<Post:0x14a6620
+ @attributes={"title"=>"Rails", "body"=>"Only ten..", "id"=>"2"}>]"
+ >> @posts.first.title = "hello from a debugger"
+ => "hello from a debugger"
+
+...and even better, you can examine how your runtime objects actually work:
+
+ >> f = @posts.first
+ => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
+ >> f.
+ Display all 152 possibilities? (y or n)
+
+Finally, when you're ready to resume execution, you can enter "cont".
+
+
+== Console
+
+The console is a Ruby shell, which allows you to interact with your
+application's domain model. Here you'll have all parts of the application
+configured, just like it is when the application is running. You can inspect
+domain models, change values, and save to the database. Starting the script
+without arguments will launch it in the development environment.
+
+To start the console, run <tt>rails console</tt> from the application
+directory.
+
+Options:
+
+* Passing the <tt>-s, --sandbox</tt> argument will rollback any modifications
+ made to the database.
+* Passing an environment name as an argument will load the corresponding
+ environment. Example: <tt>rails console production</tt>.
+
+To reload your controllers and models after launching the console run
+<tt>reload!</tt>
+
+More information about irb can be found at:
+link:http://www.rubycentral.org/pickaxe/irb.html
+
+
+== dbconsole
+
+You can go to the command line of your database directly through <tt>rails
+dbconsole</tt>. You would be connected to the database with the credentials
+defined in database.yml. Starting the script without arguments will connect you
+to the development database. Passing an argument will connect you to a different
+database, like <tt>rails dbconsole production</tt>. Currently works for MySQL,
+PostgreSQL and SQLite 3.
+
+== Description of Contents
+
+The default directory structure of a generated Ruby on Rails application:
+
+ |-- app
+ | |-- assets
+ | |-- images
+ | |-- javascripts
+ | `-- stylesheets
+ | |-- controllers
+ | |-- helpers
+ | |-- mailers
+ | |-- models
+ | `-- views
+ | `-- layouts
+ |-- config
+ | |-- environments
+ | |-- initializers
+ | `-- locales
+ |-- db
+ |-- doc
+ |-- lib
+ | `-- tasks
+ |-- log
+ |-- public
+ |-- script
+ |-- test
+ | |-- fixtures
+ | |-- functional
+ | |-- integration
+ | |-- performance
+ | `-- unit
+ |-- tmp
+ | |-- cache
+ | |-- pids
+ | |-- sessions
+ | `-- sockets
+ `-- vendor
+ |-- assets
+ `-- stylesheets
+ `-- plugins
+
+app
+ Holds all the code that's specific to this particular application.
+
+app/assets
+ Contains subdirectories for images, stylesheets, and JavaScript files.
+
+app/controllers
+ Holds controllers that should be named like weblogs_controller.rb for
+ automated URL mapping. All controllers should descend from
+ ApplicationController which itself descends from ActionController::Base.
+
+app/models
+ Holds models that should be named like post.rb. Models descend from
+ ActiveRecord::Base by default.
+
+app/views
+ Holds the template files for the view that should be named like
+ weblogs/index.html.erb for the WeblogsController#index action. All views use
+ eRuby syntax by default.
+
+app/views/layouts
+ Holds the template files for layouts to be used with views. This models the
+ common header/footer method of wrapping views. In your views, define a layout
+ using the <tt>layout :default</tt> and create a file named default.html.erb.
+ Inside default.html.erb, call <% yield %> to render the view using this
+ layout.
+
+app/helpers
+ Holds view helpers that should be named like weblogs_helper.rb. These are
+ generated for you automatically when using generators for controllers.
+ Helpers can be used to wrap functionality for your views into methods.
+
+config
+ Configuration files for the Rails environment, the routing map, the database,
+ and other dependencies.
+
+db
+ Contains the database schema in schema.rb. db/migrate contains all the
+ sequence of Migrations for your schema.
+
+doc
+ This directory is where your application documentation will be stored when
+ generated using <tt>rake doc:app</tt>
+
+lib
+ Application specific libraries. Basically, any kind of custom code that
+ doesn't belong under controllers, models, or helpers. This directory is in
+ the load path.
+
+public
+ The directory available for the web server. Also contains the dispatchers and the
+ default HTML files. This should be set as the DOCUMENT_ROOT of your web
+ server.
+
+script
+ Helper scripts for automation and generation.
+
+test
+ Unit and functional tests along with fixtures. When using the rails generate
+ command, template test files will be generated for you and placed in this
+ directory.
+
+vendor
+ External libraries that the application depends on. Also includes the plugins
+ subdirectory. If the app has frozen rails, those gems also go here, under
+ vendor/rails/. This directory is in the load path.
7 Rakefile
@@ -0,0 +1,7 @@
+#!/usr/bin/env rake
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require File.expand_path('../config/application', __FILE__)
+
+Depot::Application.load_tasks
BIN  app/assets/images/cs.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  app/assets/images/logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  app/assets/images/rails.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  app/assets/images/rtp.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  app/assets/images/ruby.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3  app/assets/javascripts/admin.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
25 app/assets/javascripts/application.js
@@ -0,0 +1,25 @@
+/***
+ * Excerpted from "Agile Web Development with Rails",
+ * published by The Pragmatic Bookshelf.
+ * Copyrights apply to this code. It may not be used to create training material,
+ * courses, books, articles, and the like. Contact us if you are in doubt.
+ * We make no guarantees that this code is fit for any purpose.
+ * Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+***/
+// This is a manifest file that'll be compiled into application.js, which will
+// include all the files listed below.
+//
+// Any JavaScript/Coffee file within this directory, lib/assets/javascripts,
+// vendor/assets/javascripts, or vendor/assets/javascripts of plugins, if any,
+// can be referenced here using a relative path.
+//
+// It's not advisable to add code directly here, but if you do, it'll appear at
+// the bottom of the the compiled file.
+//
+// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY
+// BLANK LINE SHOULD GO AFTER THE REQUIRES BELOW.
+//
+//= require jquery
+//= require jquery-ui
+//= require jquery_ujs
+//= require_tree .
3  app/assets/javascripts/carts.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
3  app/assets/javascripts/line_items.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
3  app/assets/javascripts/orders.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
3  app/assets/javascripts/products.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
3  app/assets/javascripts/sessions.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
9 app/assets/javascripts/store.js.coffee
@@ -0,0 +1,9 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
+
+//#START_HIGHLIGHT
+$ ->
+ $('.store .entry > img').click ->
+ $(this).parent().find(':submit').click()
+//#END_HIGHLIGHT
3  app/assets/javascripts/users.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
3  app/assets/stylesheets/admin.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Admin controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
135 app/assets/stylesheets/application.css.scss
@@ -0,0 +1,135 @@
+/*
+ * This is a manifest file that'll be compiled into application.css, which will
+ * include all the files listed below.
+ *
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets,
+ * vendor/assets/stylesheets, or vendor/assets/stylesheets of plugins, if any,
+ * can be referenced here using a relative path.
+ *
+ * You're free to add application-wide styles to this file and they'll appear
+ * at the top of the compiled file, but it's generally better to create a new
+ * file per style scope.
+ *
+ *= require_self
+ *= require_tree .
+*/
+
+#banner {
+ background: #9c9;
+ padding: 10px;
+ border-bottom: 2px solid;
+ font: small-caps 40px/40px "Times New Roman", serif;
+ color: #282;
+ text-align: center;
+
+ img {
+ float: left;
+ }
+}
+
+#notice {
+ color: #000 !important;
+ border: 2px solid red;
+ padding: 1em;
+ margin-bottom: 2em;
+ background-color: #f0f0f0;
+ font: bold smaller sans-serif;
+}
+
+#columns {
+ background: #141;
+
+ #main {
+ margin-left: 17em;
+ padding: 1em;
+ background: white;
+ }
+
+//#START:side
+ #side {
+ float: left;
+ padding: 1em 2em;
+ width: 13em;
+ background: #141;
+
+/* START_HIGHLIGHT */
+ form, div {
+ display: inline;
+ }
+
+ input {
+ font-size: small;
+ }
+
+ #cart {
+ font-size: smaller;
+ color: white;
+
+ table {
+ border-top: 1px dotted #595;
+ border-bottom: 1px dotted #595;
+ margin-bottom: 10px;
+ }
+ }
+
+/* END_HIGHLIGHT */
+ ul {
+ padding: 0;
+
+ li {
+ list-style: none;
+
+ a {
+ color: #bfb;
+ font-size: small;
+ }
+ }
+ }
+ }
+//#END:side
+}
+
+//#START:form
+.depot_form {
+ fieldset {
+ background: #efe;
+
+ legend {
+ color: #dfd;
+ background: #141;
+ font-family: sans-serif;
+ padding: 0.2em 1em;
+ }
+ }
+
+ form {
+ label {
+ width: 5em;
+ float: left;
+ text-align: right;
+ padding-top: 0.2em;
+ margin-right: 0.1em;
+ display: block;
+ }
+
+ select, textarea, input {
+ margin-left: 0.5em;
+ }
+
+ .submit {
+ margin-left: 4em;
+ }
+
+ br {
+ display: none
+ }
+ }
+}
+//#END:form
+
+/* START:i18n */
+.locale {
+ float: right;
+ margin: -0.25em 0.1em;
+}
+/* END:i18n */
20 app/assets/stylesheets/carts.css.scss
@@ -0,0 +1,20 @@
+// Place all the styles related to the Carts controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
+
+/* START_HIGHLIGHT */
+.carts, #side #cart {
+/* END_HIGHLIGHT */
+ .cart_title {
+ font: 120% bold;
+ }
+
+ .item_price, .total_line {
+ text-align: right;
+ }
+
+ .total_line .total_cell {
+ font-weight: bold;
+ border-top: 1px solid #595;
+ }
+}
3  app/assets/stylesheets/line_items.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the LineItems controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
3  app/assets/stylesheets/orders.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Orders controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
53 app/assets/stylesheets/products.css.scss
@@ -0,0 +1,53 @@
+// Place all the styles related to the Products controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
+
+/* START_HIGHLIGHT */
+.products {
+ table {
+ border-collapse: collapse;
+ }
+
+ table tr td {
+ padding: 5px;
+ vertical-align: top;
+ }
+
+ .list_image {
+ width: 60px;
+ height: 70px;
+ }
+
+ .list_description {
+ width: 60%;
+
+ dl {
+ margin: 0;
+ }
+
+ dt {
+ color: #244;
+ font-weight: bold;
+ font-size: larger;
+ }
+
+ dd {
+ margin: 0;
+ }
+ }
+
+ .list_actions {
+ font-size: x-small;
+ text-align: right;
+ padding-left: 1em;
+ }
+
+ .list_line_even {
+ background: #e0f8f8;
+ }
+
+ .list_line_odd {
+ background: #f8b0f8;
+ }
+}
+/* END_HIGHLIGHT */
56 app/assets/stylesheets/scaffolds.css.scss
@@ -0,0 +1,56 @@
+body {
+ background-color: #fff;
+ color: #333;
+ font-family: verdana, arial, helvetica, sans-serif;
+ font-size: 13px;
+ line-height: 18px; }
+
+p, ol, ul, td {
+ font-family: verdana, arial, helvetica, sans-serif;
+ font-size: 13px;
+ line-height: 18px; }
+
+pre {
+ background-color: #eee;
+ padding: 10px;
+ font-size: 11px; }
+
+a {
+ color: #000;
+ &:visited {
+ color: #666; }
+ &:hover {
+ color: #fff;
+ background-color: #000; } }
+
+div {
+ &.field, &.actions {
+ margin-bottom: 10px; } }
+
+#notice {
+ color: green; }
+
+.field_with_errors {
+ padding: 2px;
+ background-color: red;
+ display: table; }
+
+#error_explanation {
+ width: 450px;
+ border: 2px solid red;
+ padding: 7px;
+ padding-bottom: 0;
+ margin-bottom: 20px;
+ background-color: #f0f0f0;
+ h2 {
+ text-align: left;
+ font-weight: bold;
+ padding: 5px 5px 5px 15px;
+ font-size: 12px;
+ margin: -7px;
+ margin-bottom: 0px;
+ background-color: #c00;
+ color: #fff; }
+ ul li {
+ font-size: 12px;
+ list-style: square; } }
3  app/assets/stylesheets/sessions.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Sessions controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
57 app/assets/stylesheets/store.css.scss
@@ -0,0 +1,57 @@
+// Place all the styles related to the Store controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
+
+/* START_HIGHLIGHT */
+.store {
+ h1 {
+ margin: 0;
+ padding-bottom: 0.5em;
+ font: 150% sans-serif;
+ color: #226;
+ border-bottom: 3px dotted #77d;
+ }
+
+ /* An entry in the store catalog */
+ .entry {
+ overflow: auto;
+ margin-top: 1em;
+ border-bottom: 1px dotted #77d;
+ min-height: 100px;
+
+ img {
+ width: 80px;
+ margin-right: 5px;
+ margin-bottom: 5px;
+ position: absolute;
+ }
+
+ h3 {
+ font-size: 120%;
+ font-family: sans-serif;
+ margin-left: 100px;
+ margin-top: 0;
+ margin-bottom: 2px;
+ color: #227;
+ }
+
+//#START:inline
+ p, div.price_line {
+ margin-left: 100px;
+ margin-top: 0.5em;
+ margin-bottom: 0.8em;
+
+ form, div {
+ display: inline;
+ }
+ }
+//#END:inline
+
+ .price {
+ color: #44a;
+ font-weight: bold;
+ margin-right: 3em;
+ }
+ }
+}
+/* END_HIGHLIGHT */
3  app/assets/stylesheets/users.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Users controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
13 app/controllers/admin_controller.rb
@@ -0,0 +1,13 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class AdminController < ApplicationController
+ def index
+ @total_orders = Order.count
+ end
+end
57 app/controllers/application_controller.rb
@@ -0,0 +1,57 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class ApplicationController < ActionController::Base
+ before_filter :set_i18n_locale_from_params
+ # ...
+ before_filter :authorize
+ 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
+
+ # ...
+
+ 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 = User.find_by_name(username)
+ user && user.authenticate(password)
+ end
+ end
+ end
+
+ 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
99 app/controllers/carts_controller.rb
@@ -0,0 +1,99 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class CartsController < ApplicationController
+ skip_before_filter :authorize, only: [:create, :update, :destroy]
+
+ # GET /carts
+ # GET /carts.json
+ def index
+ @carts = Cart.all
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.json { render json: @carts }
+ end
+ end
+
+ # GET /carts/1
+ # GET /carts/1.json
+ 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.json { render json: @cart }
+ end
+ end
+ end
+
+ # GET /carts/new
+ # GET /carts/new.json
+ def new
+ @cart = Cart.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.json { render json: @cart }
+ end
+ end
+
+ # GET /carts/1/edit
+ def edit
+ @cart = Cart.find(params[:id])
+ end
+
+ # POST /carts
+ # POST /carts.json
+ def create
+ @cart = Cart.new(params[:cart])
+
+ respond_to do |format|
+ if @cart.save
+ format.html { redirect_to @cart, notice: 'Cart was successfully created.' }
+ format.json { render json: @cart, status: :created, location: @cart }
+ else
+ format.html { render action: "new" }
+ format.json { render json: @cart.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /carts/1
+ # PUT /carts/1.json
+ def update
+ @cart = Cart.find(params[:id])
+
+ respond_to do |format|
+ if @cart.update_attributes(params[:cart])
+ format.html { redirect_to @cart, notice: 'Cart was successfully updated.' }
+ format.json { head :no_content }
+ else
+ format.html { render action: "edit" }
+ format.json { render json: @cart.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /carts/1
+ # DELETE /carts/1.json
+ def destroy
+ @cart = current_cart
+ @cart.destroy
+ session[:cart_id] = nil
+
+ respond_to do |format|
+ format.html { redirect_to store_url }
+ format.json { head :no_content }
+ end
+ end
+end
106 app/controllers/line_items_controller.rb
@@ -0,0 +1,106 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class LineItemsController < ApplicationController
+ skip_before_filter :authorize, only: :create
+
+ # GET /line_items
+ # GET /line_items.json
+ def index
+ @line_items = LineItem.all
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.json { render json: @line_items }
+ format.xml { render xml: @line_items }
+ end
+ end
+
+ # GET /line_items/1
+ # GET /line_items/1.json
+ def show
+ @line_item = LineItem.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.json { render json: @line_item }
+ end
+ end
+
+ # GET /line_items/new
+ # GET /line_items/new.json
+ def new
+ @line_item = LineItem.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.json { render json: @line_item }
+ end
+ end
+
+ # GET /line_items/1/edit
+ def edit
+ @line_item = LineItem.find(params[:id])
+ end
+
+ # POST /line_items
+ # POST /line_items.json
+ def create
+ @cart = current_cart
+ if params[:line_item]
+ # ActiveResource
+ params[:line_item][:order_id] = params[:order_id]
+ @line_item = LineItem.new(params[:line_item])
+ else
+ # HTML forms
+ product = Product.find(params[:product_id])
+ @line_item = @cart.add_product(product.id)
+ end
+
+ respond_to do |format|
+ if @line_item.save
+ format.html { redirect_to store_url }
+ format.js { @current_item = @line_item }
+ format.json { render json: @line_item,
+ status: :created, location: @line_item }
+ else
+ format.html { render action: "new" }
+ format.json { render json: @line_item.errors,
+ status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /line_items/1
+ # PUT /line_items/1.json
+ def update
+ @line_item = LineItem.find(params[:id])
+
+ respond_to do |format|
+ if @line_item.update_attributes(params[:line_item])
+ format.html { redirect_to @line_item, notice: 'Line item was successfully updated.' }
+ format.json { head :no_content }
+ else
+ format.html { render action: "edit" }
+ format.json { render json: @line_item.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /line_items/1
+ # DELETE /line_items/1.json
+ def destroy
+ @line_item = LineItem.find(params[:id])
+ @line_item.destroy
+
+ respond_to do |format|
+ format.html { redirect_to line_items_url }
+ format.json { head :no_content }
+ end
+ end
+end
108 app/controllers/orders_controller.rb
@@ -0,0 +1,108 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class OrdersController < ApplicationController
+ skip_before_filter :authorize, only: [:new, :create]
+
+ # GET /orders
+ # GET /orders.json
+ 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.json { render json: @orders }
+ end
+ end
+
+ # GET /orders/1
+ # GET /orders/1.json
+ def show
+ @order = Order.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.json { render json: @order }
+ end
+ end
+
+ # GET /orders/new
+ # GET /orders/new.json
+ def new
+ @cart = current_cart
+ if @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.json { render json: @order }
+ end
+ end
+
+ # GET /orders/1/edit
+ def edit
+ @order = Order.find(params[:id])
+ end
+
+ # POST /orders
+ # POST /orders.json
+ 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
+ OrderNotifier.received(@order).deliver
+ format.html { redirect_to store_url, notice:
+ I18n.t('.thanks') }
+ format.json { render json: @order, status: :created,
+ location: @order }
+ else
+ @cart = current_cart
+ format.html { render action: "new" }
+ format.json { render json: @order.errors,
+ status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /orders/1
+ # PUT /orders/1.json
+ def update
+ @order = Order.find(params[:id])
+
+ respond_to do |format|
+ if @order.update_attributes(params[:order])
+ format.html { redirect_to @order, notice: 'Order was successfully updated.' }
+ format.json { head :no_content }
+ else
+ format.html { render action: "edit" }
+ format.json { render json: @order.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /orders/1
+ # DELETE /orders/1.json
+ def destroy
+ @order = Order.find(params[:id])
+ @order.destroy
+
+ respond_to do |format|
+ format.html { redirect_to orders_url }
+ format.json { head :no_content }
+ end
+ end
+end
107 app/controllers/products_controller.rb
@@ -0,0 +1,107 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class ProductsController < ApplicationController
+ # GET /products
+ # GET /products.json
+ def index
+ @products = Product.all
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml
+ format.json { render json: @products }
+ end
+ end
+
+ # GET /products/1
+ # GET /products/1.json
+ def show
+ @product = Product.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.json { render json: @product }
+ end
+ end
+
+ # GET /products/new
+ # GET /products/new.json
+ def new
+ @product = Product.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.json { render json: @product }
+ end
+ end
+
+ # GET /products/1/edit
+ def edit
+ @product = Product.find(params[:id])
+ end
+
+ # POST /products
+ # POST /products.json
+ 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.json { render json: @product, status: :created,
+ location: @product }
+ else
+ format.html { render action: "new" }
+ format.json { render json: @product.errors,
+ status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /products/1
+ # PUT /products/1.json
+ 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.json { head :no_content }
+ else
+ format.html { render action: "edit" }
+ format.json { render json: @product.errors,
+ status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /products/1
+ # DELETE /products/1.json
+ def destroy
+ @product = Product.find(params[:id])
+ @product.destroy
+
+ respond_to do |format|
+ format.html { redirect_to products_url }
+ format.json { head :no_content }
+ end
+ end
+
+ def who_bought
+ @product = Product.find(params[:id])
+ respond_to do |format|
+ format.html
+ format.xml
+ format.atom
+ format.json { render json: @product.to_json(include: :orders) }
+ end
+ end
+end
28 app/controllers/sessions_controller.rb
@@ -0,0 +1,28 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class SessionsController < ApplicationController
+ skip_before_filter :authorize
+ def new
+ end
+
+ def create
+ user = User.find_by_name(params[:name])
+ if user and user.authenticate(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
23 app/controllers/store_controller.rb
@@ -0,0 +1,23 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class StoreController < ApplicationController
+ skip_before_filter :authorize
+ def index
+ if params[:set_locale]
+ redirect_to store_path(locale: params[:set_locale])
+ else
+ @products = Product.order(:title)
+ @cart = current_cart
+ end
+
+ latest = Product.latest
+ fresh_when etag: latest, last_modified: latest.created_at.utc
+ expires_in 10.minutes, public: true
+ end
+end
101 app/controllers/users_controller.rb
@@ -0,0 +1,101 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class UsersController < ApplicationController
+ # GET /users
+ # GET /users.json
+ def index
+ @users = User.order(:name)
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.json { render json: @users }
+ end
+ end
+
+ # GET /users/1
+ # GET /users/1.json
+ def show
+ @user = User.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.json { render json: @user }
+ end
+ end
+
+ # GET /users/new
+ # GET /users/new.json
+ def new
+ @user = User.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.json { render json: @user }
+ end
+ end
+
+ # GET /users/1/edit
+ def edit
+ @user = User.find(params[:id])
+ end
+
+ # POST /users
+ # POST /users.json
+ 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.json { render json: @user,
+ status: :created, location: @user }
+ else
+ format.html { render action: "new" }
+ format.json { render json: @user.errors,
+ status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /users/1
+ # PUT /users/1.json
+ 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.json { head :no_content }
+ else
+ format.html { render action: "edit" }
+ format.json { render json: @user.errors,
+ status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /users/1
+ # DELETE /users/1.json
+ 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.json { head :no_content }
+ end
+ end
+end
10 app/helpers/admin_helper.rb
@@ -0,0 +1,10 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+module AdminHelper
+end
16 app/helpers/application_helper.rb
@@ -0,0 +1,16 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+module ApplicationHelper
+ def hidden_div_if(condition, attributes = {}, &block)
+ if condition
+ attributes["style"] = "display: none"
+ end
+ content_tag("div", attributes, &block)
+ end
+end
10 app/helpers/carts_helper.rb
@@ -0,0 +1,10 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+module CartsHelper
+end
10 app/helpers/line_items_helper.rb
@@ -0,0 +1,10 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+module LineItemsHelper
+end
10 app/helpers/orders_helper.rb
@@ -0,0 +1,10 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+module OrdersHelper
+end
10 app/helpers/products_helper.rb
@@ -0,0 +1,10 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+module ProductsHelper
+end
10 app/helpers/sessions_helper.rb
@@ -0,0 +1,10 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+module SessionsHelper
+end
10 app/helpers/store_helper.rb
@@ -0,0 +1,10 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+module StoreHelper
+end
10 app/helpers/users_helper.rb
@@ -0,0 +1,10 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+module UsersHelper
+end
0  app/mailers/.gitkeep
No changes.
33 app/mailers/order_notifier.rb
@@ -0,0 +1,33 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class OrderNotifier < 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.order_notifier.received.subject
+ #
+ def 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.order_notifier.shipped.subject
+ #
+ def shipped(order)
+ @order = order
+
+ mail to: order.email, subject: 'Pragmatic Store Order Shipped'
+ end
+end
0  app/models/.gitkeep
No changes.
26 app/models/cart.rb
@@ -0,0 +1,26 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class Cart < ActiveRecord::Base
+ has_many :line_items, dependent: :destroy
+
+ def add_product(product_id)
+ current_item = line_items.find_by_product_id(product_id)
+ if current_item
+ current_item.quantity += 1
+ else
+ current_item = line_items.build(product_id: product_id)
+ current_item.price = current_item.product.price
+ end
+ current_item
+ end
+
+ def total_price
+ line_items.to_a.sum { |item| item.total_price }
+ end
+end
17 app/models/line_item.rb
@@ -0,0 +1,17 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class LineItem < ActiveRecord::Base
+ belongs_to :order
+ belongs_to :product
+ belongs_to :cart
+
+ def total_price
+ product.price * quantity
+ end
+end
21 app/models/order.rb
@@ -0,0 +1,21 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class Order < ActiveRecord::Base
+ PAYMENT_TYPES = [ "Check", "Credit card", "Purchase order" ]
+ has_many :line_items, dependent: :destroy
+ # ...
+ validates :name, :address, :email, presence: true
+ validates :pay_type, inclusion: PAYMENT_TYPES
+ def add_line_items_from_cart(cart)
+ cart.line_items.each do |item|
+ item.cart_id = nil
+ line_items << item
+ end
+ end
+end
42 app/models/product.rb
@@ -0,0 +1,42 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class Product < ActiveRecord::Base
+ has_many :line_items
+ has_many :orders, through: :line_items
+ #...
+
+ before_destroy :ensure_not_referenced_by_any_line_item
+
+ 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.'
+ }
+ validates :title, length: {minimum: 10}
+ def self.latest
+ Product.order('updated_at desc').limit(1).first
+ end
+
+
+
+ private
+
+ # ensure that there are no line items referencing this product
+ def ensure_not_referenced_by_any_line_item
+ if line_items.empty?
+ return true
+ else
+ errors.add(:base, 'Line Items present')
+ return false
+ end
+ end
+end
21 app/models/user.rb
@@ -0,0 +1,21 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class User < ActiveRecord::Base
+ validates :name, presence: true, uniqueness: true
+ has_secure_password
+
+ after_destroy :ensure_an_admin_remains
+
+ private
+ def ensure_an_admin_remains
+ if User.count.zero?
+ raise "Can't delete last user"
+ end
+ end
+end
33 app/store.rb
@@ -0,0 +1,33 @@
+#---
+# Excerpted from "Agile Web Development with Rails",
+# published by The Pragmatic Bookshelf.
+# Copyrights apply to this code. It may not be used to create training material,
+# courses, books, articles, and the like. Contact us if you are in doubt.
+# We make no guarantees that this code is fit for any purpose.
+# Visit http://www.pragmaticprogrammer.com/titles/rails4 for more book information.
+#---
+class StoreApp
+ def call(env)
+ x = Builder::XmlMarkup.new :indent=>2
+
+ x.declare! :DOCTYPE, :html
+ x.html do
+ x.head do
+ x.title 'Pragmatic Bookshelf'
+ end
+ x.body do
+ x.h1 'Pragmatic Bookshelf'
+
+ Product.all.each do |product|
+ x.h2 product.title
+ x << " #{product.description}\n"
+ x.p product.price
+ end
+ end
+ end
+
+ response = Rack::Response.new(x.target!)
+ response['Content-Type'] = 'text/html'
+ response.finish
+ end
+end
4 app/views/admin/index.html.erb
@@ -0,0 +1,4 @@
+<h1>Welcome</h1>
+
+It's <%= Time.now %>
+We have <%= pluralize(@total_orders, "order") %>.
20 app/views/carts/_cart.html.erb
@@ -0,0 +1,20 @@
+<!-- START_HIGHLIGHT -->
+<div class="cart_title"><%= t('.title') %></div>
+<!-- END_HIGHLIGHT -->
+<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>
+
+<!-- START_HIGHLIGHT -->
+<%= button_to t('.checkout'), new_order_path, method: :get %>
+<!-- END_HIGHLIGHT -->
+<!-- START_HIGHLIGHT -->
+<%= button_to t('.empty'), cart, method: :delete,
+# END_HIGHLIGHT
+ confirm: 'Are you sure?' %>
17 app/views/carts/_form.html.erb
@@ -0,0 +1,17 @@
+<%= form_for(@cart) do |f| %>
+ <% if @cart.errors.any? %>
+ <div id="error_explanation">
+ <h2><%= pluralize(@cart.errors.count, "error") %> prohibited this cart from being saved:</h2>
+
+ <ul>
+ <% @cart.errors.full_messages.each do |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div class="actions">
+ <%= f.submit %>
+ </div>
+<% end %>
6 app/views/carts/edit.html.erb
@@ -0,0 +1,6 @@
+<h1>Editing cart</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Show', @cart %> |
+<%= link_to 'Back', carts_path %>
21 app/views/carts/index.html.erb
@@ -0,0 +1,21 @@
+<h1>Listing carts</h1>
+
+<table>
+ <tr>
+ <th></th>
+ <th></th>
+ <th></th>
+ </tr>
+
+<% @carts.each do |cart| %>
+ <tr>
+ <td><%= link_to 'Show', cart %></td>
+ <td><%= link_to 'Edit', edit_cart_path(cart) %></td>
+ <td><%= link_to 'Destroy', cart, confirm: 'Are you sure?', method: :delete %></td>
+ </tr>
+<% end %>
+</table>
+
+<br />
+
+<%= link_to 'New Cart', new_cart_path %>
5 app/views/carts/new.html.erb
@@ -0,0 +1,5 @@
+<h1>New cart</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Back', carts_path %>
7 app/views/carts/show.html.erb
@@ -0,0 +1,7 @@
+<% if notice %>
+<p id="notice"><%= notice %></p>
+<% end %>
+
+<!-- START_HIGHLIGHT -->
+<%= render @cart %>
+<!-- END_HIGHLIGHT -->
58 app/views/layouts/application.html.erb
@@ -0,0 +1,58 @@
+<!-- START:head -->
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Pragprog Books Online Store</title>
+ <%= stylesheet_link_tag "application" %>
+ <%= javascript_include_tag "application" %>
+ <%= csrf_meta_tag %>
+</head>
+<!-- END:head -->
+<body class="<%= controller.controller_name %>">
+<!-- START:i18n -->
+ <div id="banner">
+<!-- START_HIGHLIGHT -->
+ <%= 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').hide()" %>
+ <% end %>
+<!-- END_HIGHLIGHT -->
+ <%= image_tag("logo.png") %>
+ <%= @page_title || t('.title') %>
+ </div>
+<!-- END:i18n -->
+ <div id="columns">
+ <div id="side">
+ <!-- START:hidden_div -->
+ <% if @cart %>
+ <%= hidden_div_if(@cart.line_items.empty?, id: 'cart') do %>
+ <%= render @cart %>
+ <% end %>
+ <% end %>
+ <!-- END:hidden_div -->
+
+ <ul>
+ <li><a href="http://www...."><%= t('.home') %></a></li>
+ <li><a href="http://www..../faq"><%= t('.questions') %></a></li>
+ <li><a href="http://www..../news"><%= t('.news') %></a></li>
+ <li><a href="http://www..../contact"><%= t('.contact') %></a></li>
+ </ul>
+
+ <% if session[:user_id] %>
+ <ul>
+ <li><%= link_to 'Orders', orders_path %></li>
+ <li><%= link_to 'Products', products_path %></li>
+ <li><%= link_to 'Users', users_path %></li>
+ </ul>
+ <%= button_to 'Logout', logout_path, method: :delete %>
+ <% end %>
+ </div>
+ <div id="main">
+ <%= yield %>
+ </div>
+ </div>
+</body>
+</html>
25 app/views/line_items/_form.html.erb
@@ -0,0 +1,25 @@
+<%= form_for(@line_item) do |f| %>
+ <% if @line_item.errors.any? %>
+ <div id="error_explanation">
+ <h2><%= pluralize(@line_item.errors.count, "error") %> prohibited this line_item from being saved:</h2>
+
+ <ul>
+ <% @line_item.errors.full_messages.each do |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div class="field">
+ <%= f.label :product_id %><br />
+ <%= f.number_field :product_id %>
+ </div>
+ <div class="field">
+ <%= f.label :cart_id %><br />
+ <%= f.number_field :cart_id %>
+ </div>
+ <div class="actions">
+ <%= f.submit %>
+ </div>
+<% end %>
9 app/views/line_items/_line_item.html.erb
@@ -0,0 +1,9 @@
+<% 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>
3  app/views/line_items/_line_item.text.erb
@@ -0,0 +1,3 @@
+<%= sprintf("%2d x %s",
+ line_item.quantity,
+ truncate(line_item.product.title, length: 50)) %>
10 app/views/line_items/create.js.erb
@@ -0,0 +1,10 @@
+//#START_HIGHLIGHT
+$("#notice").hide();
+
+//#END_HIGHLIGHT
+if ($('#cart tr').length == 1) { $('#cart').show('blind', 1000); }
+
+$('#cart').html("<%=j render @cart %>");
+
+$('#current_item').css({'background-color':'#88ff88'}).
+ animate({'background-color':'#114411'}, 1000);
6 app/views/line_items/edit.html.erb
@@ -0,0 +1,6 @@
+<h1>Editing line_item</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Show', @line_item %> |
+<%= link_to 'Back', line_items_path %>
25 app/views/line_items/index.html.erb
@@ -0,0 +1,25 @@
+<h1>Listing line_items</h1>
+
+<table>
+ <tr>
+ <th>Product</th>
+ <th>Cart</th>
+ <th></th>
+ <th></th>
+ <th></th>
+ </tr>
+
+<% @line_items.each do |line_item| %>
+ <tr>
+ <td><%= line_item.product_id %></td>
+ <td><%= line_item.cart_id %></td>
+ <td><%= link_to 'Show', line_item %></td>
+ <td><%= link_to 'Edit', edit_line_item_path(line_item) %></td>
+ <td><%= link_to 'Destroy', line_item, confirm: 'Are you sure?', method: :delete %></td>
+ </tr>
+<% end %>
+</table>
+
+<br />
+
+<%= link_to 'New Line item', new_line_item_path %>
5 app/views/line_items/new.html.erb
@@ -0,0 +1,5 @@
+<h1>New line_item</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Back', line_items_path %>
15 app/views/line_items/show.html.erb
@@ -0,0 +1,15 @@
+<p id="notice"><%= notice %></p>
+
+<p>
+ <b>Product:</b>
+ <%= @line_item.product_id %>
+</p>
+
+<p>
+ <b>Cart:</b>
+ <%= @line_item.cart_id %>
+</p>
+
+
+<%= link_to 'Edit', edit_line_item_path(@line_item) %> |
+<%= link_to 'Back', line_items_path %>
9 app/views/order_notifier/received.text.erb
@@ -0,0 +1,9 @@
+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.
9 app/views/order_notifier/shipped.html.erb
@@ -0,0 +1,9 @@
+<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>
3  app/views/order_notifier/shipped.text.erb
@@ -0,0 +1,3 @@
+OrderNotifier#shipped
+
+<%= @greeting %>, find me in app/views/app/views/order_notifier/shipped.text.erb
49 app/views/orders/_form.html.erb
@@ -0,0 +1,49 @@
+<!-- START:explanation -->
+<%= form_for(@order) do |f| %>
+ <% if @order.errors.any? %>
+ <div id="error_explanation">
+<!-- START_HIGHLIGHT -->
+ <h2><%=raw t('errors.template.header', count: @order.errors.count,
+ model: t('activerecord.models.order')) %>.</h2>
+ <p><%= t('errors.template.body') %></p>
+<!-- END_HIGHLIGHT -->
+
+ <ul>
+ <% @order.errors.full_messages.each do |msg| %>
+<!-- START_HIGHLIGHT -->
+ <li><%=raw msg %></li>
+<!-- END_HIGHLIGHT -->
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+<!-- ... -->
+<!-- END:explanation -->
+
+ <div class="field">
+ <%= f.label :name %><br />
+ <%= f.text_field :name, size: 40 %>
+ </div>
+ <div class="field">
+<!-- START_HIGHLIGHT -->
+ <%= f.label :address, t('.address_html') %><br />
+<!-- END_HIGHLIGHT -->
+ <%= f.text_area :address, rows: 3, cols: 40 %>
+ </div>
+ <div class="field">
+ <%= f.label :email %><br />
+ <%= f.email_field :email, size: 40 %>
+ </div>
+ <div class="field">
+ <%= f.label :pay_type %><br />
+ <%= f.select :pay_type, Order::PAYMENT_TYPES,
+#START_HIGHLIGHT
+ prompt: t('.pay_prompt_html') %>
+<!-- END_HIGHLIGHT -->
+ </div>
+ <div class="actions">
+<!-- START_HIGHLIGHT -->
+ <%= f.submit t('.submit') %>
+<!-- END_HIGHLIGHT -->
+ </div>
+<% end %>
6 app/views/orders/edit.html.erb
@@ -0,0 +1,6 @@
+<h1>Editing order</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Show', @order %> |
+<%= link_to 'Back', orders_path %>
33 app/views/orders/index.html.erb
@@ -0,0 +1,33 @@
+<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 %>
+<!-- START_HIGHLIGHT -->
+<p><%= will_paginate @orders %></p>
+<!-- END_HIGHLIGHT -->
8 app/views/orders/new.html.erb
@@ -0,0 +1,8 @@
+<div class="depot_form">
+ <fieldset>
+<!-- START_HIGHLIGHT -->
+ <legend><%= t('.legend') %></legend>
+<!-- END_HIGHLIGHT -->
+ <%= render 'form' %>
+ </fieldset>
+</div>
25 app/views/orders/show.html.erb
@@ -0,0 +1,25 @@
+<p id="notice"><%= notice %></p>
+
+<p>
+ <b>Name:</b>
+ <%= @order.name %>
+</p>
+
+<p>
+ <b>Address:</b>
+ <%= @order.address %>
+</p>
+
+<p>
+ <b>Email:</b>
+ <%= @order.email %>
+</p>
+
+<p>
+ <b>Pay type:</b>
+ <%= @order.pay_type %>
+</p>
+
+
+<%= link_to 'Edit', edit_order_path(@order) %> |
+<%= link_to 'Back', orders_path %>
36 app/views/products/_form.html.erb
@@ -0,0 +1,36 @@
+<%= form_for(@product) do |f| %>