Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 8763add340c8756db6d34e75ddc16452e788a748 0 parents
Yehuda Katz + Carl Lerche authored Carl Lerche committed
Showing with 17,918 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +243 −0 README
  3. +10 −0 Rakefile
  4. +34 −0 app/controllers/admin_controller.rb
  5. +57 −0 app/controllers/application_controller.rb
  6. +17 −0 app/controllers/info_controller.rb
  7. +93 −0 app/controllers/line_items_controller.rb
  8. +85 −0 app/controllers/orders_controller.rb
  9. +85 −0 app/controllers/products_controller.rb
  10. +86 −0 app/controllers/store_controller.rb
  11. +103 −0 app/controllers/users_controller.rb
  12. +2 −0  app/helpers/admin_helper.rb
  13. +3 −0  app/helpers/application_helper.rb
  14. +2 −0  app/helpers/info_helper.rb
  15. +2 −0  app/helpers/line_items_helper.rb
  16. +2 −0  app/helpers/orders_helper.rb
  17. +2 −0  app/helpers/products_helper.rb
  18. +8 −0 app/helpers/store_helper.rb
  19. +2 −0  app/helpers/users_helper.rb
  20. +32 −0 app/models/cart.rb
  21. +21 −0 app/models/cart_item.rb
  22. +17 −0 app/models/line_item.rb
  23. +39 −0 app/models/order.rb
  24. +48 −0 app/models/product.rb
  25. +72 −0 app/models/user.rb
  26. +4 −0 app/views/admin/index.html.erb
  27. +21 −0 app/views/admin/login.html.erb
  28. +2 −0  app/views/admin/logout.html.erb
  29. +39 −0 app/views/info/who_bought.atom.builder
  30. +9 −0 app/views/info/who_bought.html.erb
  31. +8 −0 app/views/info/who_bought.xml.builder
  32. +17 −0 app/views/layouts/line_items.html.erb
  33. +70 −0 app/views/layouts/store.html.erb
  34. +28 −0 app/views/line_items/edit.html.erb
  35. +26 −0 app/views/line_items/index.html.erb
  36. +27 −0 app/views/line_items/new.html.erb
  37. +23 −0 app/views/line_items/show.html.erb
  38. +28 −0 app/views/orders/edit.html.erb
  39. +26 −0 app/views/orders/index.html.erb
  40. +27 −0 app/views/orders/new.html.erb
  41. +23 −0 app/views/orders/show.html.erb
  42. +31 −0 app/views/products/edit.html.erb
  43. +34 −0 app/views/products/index.html.erb
  44. +30 −0 app/views/products/new.html.erb
  45. +24 −0 app/views/products/show.html.erb
  46. +19 −0 app/views/store/_cart.html.erb
  47. +11 −0 app/views/store/_cart_item.html.erb
  48. +11 −0 app/views/store/add_to_cart.js.rjs
  49. +50 −0 app/views/store/checkout.html.erb
  50. +21 −0 app/views/store/index.html.erb
  51. +24 −0 app/views/users/edit.html.erb
  52. +21 −0 app/views/users/index.html.erb
  53. +31 −0 app/views/users/new.html.erb
  54. +18 −0 app/views/users/show.html.erb
  55. +110 −0 config/boot.rb
  56. +22 −0 config/database.sample.yml
  57. +41 −0 config/environment.rb
  58. +19 −0 config/environments/development.rb
  59. +27 −0 config/environments/production.rb
  60. +27 −0 config/environments/test.rb
  61. +7 −0 config/initializers/backtrace_silencers.rb
  62. +8 −0 config/initializers/i18n.rb
  63. +10 −0 config/initializers/inflections.rb
  64. +5 −0 config/initializers/mime_types.rb
  65. +19 −0 config/initializers/new_rails_defaults.rb
  66. +17 −0 config/initializers/session_store.rb
  67. +64 −0 config/locales/en.yml
  68. +93 −0 config/locales/es.yml
  69. +51 −0 config/routes.rb
  70. BIN  db/default/development.sqlite3
  71. +15 −0 db/migrate/20080601000001_create_products.rb
  72. +10 −0 db/migrate/20080601000002_add_price_to_product.rb
  73. +63 −0 db/migrate/20080601000003_add_test_data.rb
  74. +16 −0 db/migrate/20080601000004_create_sessions.rb
  75. +20 −0 db/migrate/20080601000005_create_orders.rb
  76. +20 −0 db/migrate/20080601000006_create_line_items.rb
  77. +15 −0 db/migrate/20080601000007_create_users.rb
  78. +59 −0 db/schema.rb
  79. +7 −0 db/seeds.rb
  80. +2 −0  doc/README_FOR_APP
  81. +219 −0 doc/app/classes/AdminController.html
  82. +105 −0 doc/app/classes/AdminHelper.html
  83. +158 −0 doc/app/classes/ApplicationController.html
  84. +112 −0 doc/app/classes/ApplicationHelper.html
  85. +249 −0 doc/app/classes/Cart.html
  86. +239 −0 doc/app/classes/CartItem.html
  87. +184 −0 doc/app/classes/InfoController.html
  88. +105 −0 doc/app/classes/InfoHelper.html
  89. +159 −0 doc/app/classes/LineItem.html
  90. +356 −0 doc/app/classes/LineItemsController.html
  91. +105 −0 doc/app/classes/LineItemsHelper.html
  92. +176 −0 doc/app/classes/Order.html
  93. +356 −0 doc/app/classes/OrdersController.html
  94. +105 −0 doc/app/classes/OrdersHelper.html
  95. +188 −0 doc/app/classes/Product.html
  96. +356 −0 doc/app/classes/ProductsController.html
  97. +105 −0 doc/app/classes/ProductsHelper.html
  98. +314 −0 doc/app/classes/StoreController.html
  99. +143 −0 doc/app/classes/StoreHelper.html
  100. +263 −0 doc/app/classes/User.html
  101. +377 −0 doc/app/classes/UsersController.html
  102. +105 −0 doc/app/classes/UsersHelper.html
  103. +1 −0  doc/app/created.rid
  104. +101 −0 doc/app/files/app/controllers/admin_controller_rb.html
  105. +109 −0 doc/app/files/app/controllers/application_controller_rb.html
  106. +101 −0 doc/app/files/app/controllers/info_controller_rb.html
  107. +101 −0 doc/app/files/app/controllers/line_items_controller_rb.html
  108. +101 −0 doc/app/files/app/controllers/orders_controller_rb.html
  109. +101 −0 doc/app/files/app/controllers/products_controller_rb.html
  110. +107 −0 doc/app/files/app/controllers/store_controller_rb.html
  111. +101 −0 doc/app/files/app/controllers/users_controller_rb.html
  112. +101 −0 doc/app/files/app/helpers/admin_helper_rb.html
  113. +108 −0 doc/app/files/app/helpers/application_helper_rb.html
  114. +101 −0 doc/app/files/app/helpers/info_helper_rb.html
  115. +101 −0 doc/app/files/app/helpers/line_items_helper_rb.html
  116. +101 −0 doc/app/files/app/helpers/orders_helper_rb.html
  117. +101 −0 doc/app/files/app/helpers/products_helper_rb.html
  118. +101 −0 doc/app/files/app/helpers/store_helper_rb.html
  119. +101 −0 doc/app/files/app/helpers/users_helper_rb.html
  120. +101 −0 doc/app/files/app/models/cart_item_rb.html
  121. +101 −0 doc/app/files/app/models/cart_rb.html
  122. +107 −0 doc/app/files/app/models/line_item_rb.html
  123. +107 −0 doc/app/files/app/models/order_rb.html
  124. +107 −0 doc/app/files/app/models/product_rb.html
  125. +108 −0 doc/app/files/app/models/user_rb.html
  126. +110 −0 doc/app/files/doc/README_FOR_APP.html
  127. +48 −0 doc/app/fr_class_index.html
  128. +49 −0 doc/app/fr_file_index.html
  129. +83 −0 doc/app/fr_method_index.html
  130. +24 −0 doc/app/index.html
  131. +208 −0 doc/app/rdoc-style.css
  132. +7 −0 lib/tasks/db_schema_migrations.rake
  133. +30 −0 public/404.html
  134. +30 −0 public/422.html
  135. +30 −0 public/500.html
  136. 0  public/favicon.ico
  137. BIN  public/images/auto.jpg
  138. BIN  public/images/logo.png
  139. BIN  public/images/rails.png
  140. BIN  public/images/svn.jpg
  141. BIN  public/images/utc.jpg
  142. +280 −0 public/index.html
  143. +2 −0  public/javascripts/application.js
  144. +963 −0 public/javascripts/controls.js
  145. +973 −0 public/javascripts/dragdrop.js
  146. +1,128 −0 public/javascripts/effects.js
  147. +4,320 −0 public/javascripts/prototype.js
  148. +5 −0 public/robots.txt
  149. +276 −0 public/stylesheets/depot.css
  150. +54 −0 public/stylesheets/scaffold.css
  151. +4 −0 script/about
  152. +3 −0  script/console
  153. +3 −0  script/dbconsole
  154. +3 −0  script/destroy
  155. +3 −0  script/generate
  156. +3 −0  script/performance/benchmarker
  157. +3 −0  script/performance/profiler
  158. +3 −0  script/plugin
  159. +3 −0  script/runner
  160. +3 −0  script/server
4 .gitignore
@@ -0,0 +1,4 @@
+config/database.yml
+db/*.sqlite3
+log
+tmp
243 README
@@ -0,0 +1,243 @@
+== 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, start a new Rails application using the <tt>rails</tt> command
+ and your application name. Ex: rails myapp
+2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options)
+3. Go to http://localhost:3000/ and get "Welcome aboard: You're riding the Rails!"
+4. Follow the guidelines to start developing your application
+
+
+== Web Servers
+
+By default, Rails will try to use Mongrel if it's are installed when started with script/server, otherwise Rails will use WEBrick, the webserver that ships with Ruby. But you can also use Rails
+with a variety of other web servers.
+
+Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is
+suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
+getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
+More info at: http://mongrel.rubyforge.org
+
+Say other Ruby web servers like Thin and Ebb or regular web servers like Apache or LiteSpeed or
+Lighttpd or IIS. The Ruby web servers are run through Rack and the latter can either be setup to use
+FCGI or proxy to a pack of Mongrels/Thin/Ebb servers.
+
+== Apache .htaccess example for FCGI/CGI
+
+# General Apache options
+AddHandler fastcgi-script .fcgi
+AddHandler cgi-script .cgi
+Options +FollowSymLinks +ExecCGI
+
+# If you don't want Rails to look in certain directories,
+# use the following rewrite rules so that Apache won't rewrite certain requests
+#
+# Example:
+# RewriteCond %{REQUEST_URI} ^/notrails.*
+# RewriteRule .* - [L]
+
+# Redirect all requests not available on the filesystem to Rails
+# By default the cgi dispatcher is used which is very slow
+#
+# For better performance replace the dispatcher with the fastcgi one
+#
+# Example:
+# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
+RewriteEngine On
+
+# If your Rails application is accessed via an Alias directive,
+# then you MUST also set the RewriteBase in this htaccess file.
+#
+# Example:
+# Alias /myrailsapp /path/to/myrailsapp/public
+# RewriteBase /myrailsapp
+
+RewriteRule ^$ index.html [QSA]
+RewriteRule ^([^.]+)$ $1.html [QSA]
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
+
+# In case Rails experiences terminal errors
+# Instead of displaying this message you can supply a file here which will be rendered instead
+#
+# Example:
+# ErrorDocument 500 /500.html
+
+ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
+
+
+== 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/ including:
+
+* The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/
+* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
+
+These two online (and free) 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 'gem install ruby-debug'
+Example:
+
+ class WeblogController < ActionController::Base
+ def index
+ @posts = Post.find(: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 you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
+ >> @posts.first.title = "hello from a debugger"
+ => "hello from a debugger"
+
+...and even better is that 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 enter "cont"
+
+
+== Console
+
+You can interact with the domain model by starting the console through <tt>script/console</tt>.
+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.
+Passing an argument will specify a different environment, like <tt>script/console production</tt>.
+
+To reload your controllers and models after launching the console run <tt>reload!</tt>
+
+== dbconsole
+
+You can go to the command line of your database directly through <tt>script/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>script/dbconsole production</tt>.
+Currently works for mysql, postgresql and sqlite.
+
+== Description of Contents
+
+app
+ Holds all the code that's specific to this particular application.
+
+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.
+ Most models will descend from ActiveRecord::Base.
+
+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.
+
+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 script/generate 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. Contains subdirectories for images, stylesheets,
+ and javascripts. 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 script/generate scripts, 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.
10 Rakefile
@@ -0,0 +1,10 @@
+# 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.join(File.dirname(__FILE__), 'config', 'boot'))
+
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+require 'tasks/rails'
34 app/controllers/admin_controller.rb
@@ -0,0 +1,34 @@
+class AdminController < ApplicationController
+
+ # just display the form and wait for user to
+ # enter a name and password
+ #START:login
+ def login
+ if request.post?
+ user = User.authenticate(params[:name], params[:password])
+ if user
+ session[:user_id] = user.id
+ redirect_to(:action => "index")
+ else
+ flash.now[:notice] = "Invalid user/password combination"
+ end
+ end
+ end
+ #END:login
+
+ #START:logout
+ def logout
+#START_HIGHLIGHT
+ session[:user_id] = :logged_out
+#END_HIGHLIGHT
+ flash[:notice] = "Logged out"
+ redirect_to(:action => "login")
+ end
+ #END:logout
+
+ #START:index
+ def index
+ @total_orders = Order.count
+ end
+ #END:index
+end
57 app/controllers/application_controller.rb
@@ -0,0 +1,57 @@
+# Filters added to this controller apply to all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+
+#START:auth
+class ApplicationController < ActionController::Base
+ layout "store"
+ before_filter :authorize, :except => :login
+ #...
+
+#END:auth
+ before_filter :set_locale
+ helper :all # include all helpers, all the time
+ protect_from_forgery # See ActionController::RequestForgeryProtection for details
+
+ # Scrub sensitive parameters from your log
+ # filter_parameter_logging :password
+#START:auth
+
+protected
+ def authorize
+ unless User.find_by_id(session[:user_id])
+ #START_HIGHLIGHT
+ if session[:user_id] != :logged_out
+ #START:basic
+ authenticate_or_request_with_http_basic('Depot') do |username, password|
+ user = User.authenticate(username, password)
+ session[:user_id] = user.id if user
+ end
+ #END:basic
+ else
+ flash[:notice] = "Please log in"
+ redirect_to :controller => 'admin', :action => 'login'
+ end
+ #END_HIGHLIGHT
+ end
+ end
+
+ def set_locale
+ session[:locale] = params[:locale] if params[:locale]
+ I18n.locale = session[:locale] || I18n.default_locale
+
+ locale_path = "#{LOCALES_DIRECTORY}#{I18n.locale}.yml"
+
+ unless I18n.load_path.include? locale_path
+ I18n.load_path << locale_path
+ I18n.backend.send(:init_translations)
+ end
+
+ rescue Exception => err
+ logger.error err
+ flash.now[:notice] = "#{I18n.locale} translation not available"
+
+ I18n.load_path -= [locale_path]
+ I18n.locale = session[:locale] = I18n.default_locale
+ end
+end
+#END:auth
17 app/controllers/info_controller.rb
@@ -0,0 +1,17 @@
+class InfoController < ApplicationController
+ #START:who_bought
+ def who_bought
+ @product = Product.find(params[:id])
+ @orders = @product.orders
+ respond_to do |format|
+ format.html
+ format.xml { render :layout => false }
+ end
+ end
+ #END:who_bought
+
+protected
+
+ def authorize
+ end
+end
93 app/controllers/line_items_controller.rb
@@ -0,0 +1,93 @@
+class LineItemsController < ApplicationController
+ # GET /line_items
+ # GET /line_items.xml
+ def index
+ @line_items = LineItem.all
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml { render :xml => @line_items }
+ end
+ end
+
+ # GET /line_items/1
+ # GET /line_items/1.xml
+ def show
+ @line_item = LineItem.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.xml { render :xml => @line_item }
+ end
+ end
+
+ # GET /line_items/new
+ # GET /line_items/new.xml
+ def new
+ @line_item = LineItem.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.xml { render :xml => @line_item }
+ end
+ end
+
+ # GET /line_items/1/edit
+ def edit
+ @line_item = LineItem.find(params[:id])
+ end
+
+ # POST /line_items
+ # POST /line_items.xml
+#START:create
+ def create
+ #START_HIGHLIGHT
+ params[:line_item][:order_id] ||= params[:order_id]
+ #END_HIGHLIGHT
+ @line_item = LineItem.new(params[:line_item])
+
+ respond_to do |format|
+ if @line_item.save
+ flash[:notice] = 'LineItem was successfully created.'
+ format.html { redirect_to(@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
+#END:create
+
+ # PUT /line_items/1
+ # PUT /line_items/1.xml
+ def update
+ @line_item = LineItem.find(params[:id])
+
+ respond_to do |format|
+ if @line_item.update_attributes(params[:line_item])
+ flash[:notice] = 'LineItem was successfully updated.'
+ format.html { redirect_to(@line_item) }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @line_item.errors,
+ :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /line_items/1
+ # DELETE /line_items/1.xml
+ def destroy
+ @line_item = LineItem.find(params[:id])
+ @line_item.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(line_items_url) }
+ format.xml { head :ok }
+ end
+ end
+end
85 app/controllers/orders_controller.rb
@@ -0,0 +1,85 @@
+class OrdersController < ApplicationController
+ # GET /orders
+ # GET /orders.xml
+ def index
+ @orders = Order.all
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml { render :xml => @orders }
+ end
+ end
+
+ # GET /orders/1
+ # GET /orders/1.xml
+ def show
+ @order = Order.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.xml { render :xml => @order }
+ end
+ end
+
+ # GET /orders/new
+ # GET /orders/new.xml
+ def new
+ @order = Order.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.xml { render :xml => @order }
+ end
+ end
+
+ # GET /orders/1/edit
+ def edit
+ @order = Order.find(params[:id])
+ end
+
+ # POST /orders
+ # POST /orders.xml
+ def create
+ @order = Order.new(params[:order])
+
+ respond_to do |format|
+ if @order.save
+ flash[:notice] = 'Order was successfully created.'
+ format.html { redirect_to(@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
+
+ # PUT /orders/1
+ # PUT /orders/1.xml
+ def update
+ @order = Order.find(params[:id])
+
+ respond_to do |format|
+ if @order.update_attributes(params[:order])
+ flash[:notice] = 'Order was successfully updated.'
+ format.html { redirect_to(@order) }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @order.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /orders/1
+ # DELETE /orders/1.xml
+ def destroy
+ @order = Order.find(params[:id])
+ @order.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(orders_url) }
+ format.xml { head :ok }
+ end
+ end
+end
85 app/controllers/products_controller.rb
@@ -0,0 +1,85 @@
+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
+ flash[:notice] = 'Product was successfully created.'
+ format.html { redirect_to(@product) }
+ 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])
+ flash[:notice] = 'Product was successfully updated.'
+ format.html { redirect_to(@product) }
+ 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
86 app/controllers/store_controller.rb
@@ -0,0 +1,86 @@
+#START:authorize
+class StoreController < ApplicationController
+#END:authorize
+ #START:before_filter
+ before_filter :find_cart, :except => :empty_cart
+ #END:before_filter
+ #START:index
+ def index
+ @products = Product.find_products_for_sale
+ end
+ #END:index
+
+
+ #START:rti
+ #START:add_to_cart
+ def add_to_cart
+ product = Product.find(params[:id])
+ @current_item = @cart.add_product(product)
+ respond_to do |format|
+ format.js if request.xhr?
+ format.html {redirect_to_index}
+ end
+ rescue ActiveRecord::RecordNotFound
+ logger.error("Attempt to access invalid product #{params[:id]}")
+ redirect_to_index("Invalid product")
+ end
+ #END:add_to_cart
+
+#START:cart
+ #START:empty_cart
+ #START:checkout
+ def checkout
+ if @cart.items.empty?
+ redirect_to_index("Your cart is empty")
+ else
+ @order = Order.new
+ end
+ end
+ #END:checkout
+
+ #START:save_order
+ def save_order
+ @order = Order.new(params[:order])
+ @order.add_line_items_from_cart(@cart)
+ if @order.save
+ session[:cart] = nil
+# START_HIGHLIGHT
+ redirect_to_index(I18n.t('flash.thanks'))
+# END_HIGHLIGHT
+ else
+ render :action => 'checkout'
+ end
+ end
+ #END:save_order
+
+ def empty_cart
+ session[:cart] = nil
+ redirect_to_index
+ end
+ #END:empty_cart
+
+private
+
+ #START:redirect_to_index
+ def redirect_to_index(msg = nil)
+ flash[:notice] = msg if msg
+ redirect_to :action => 'index'
+ end
+ #END:redirect_to_index
+ #END:rti
+
+ #START:find_cart
+ def find_cart
+ @cart = (session[:cart] ||= Cart.new)
+ end
+ #END:find_cart
+#END:cart
+
+#START:authorize
+ #...
+protected
+
+ def authorize
+ end
+end
+#END:authorize
103 app/controllers/users_controller.rb
@@ -0,0 +1,103 @@
+class UsersController < ApplicationController
+ # GET /users
+ # GET /users.xml
+ def index
+#START_HIGHLIGHT
+ @users = User.all(:order => :name)
+#END_HIGHLIGHT
+
+ 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
+#START_HIGHLIGHT
+ flash[:notice] = "User #{@user.name} was successfully created."
+ format.html { redirect_to(:action=>'index') }
+#END_HIGHLIGHT
+ 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])
+#START_HIGHLIGHT
+ flash[:notice] = "User #{@user.name} was successfully updated."
+ format.html { redirect_to(:action=>'index') }
+#END_HIGHLIGHT
+ 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
+ #START:delete_user
+ def destroy
+ @user = User.find(params[:id])
+ #START_HIGHLIGHT
+ begin
+ @user.destroy
+ flash[:notice] = "User #{@user.name} deleted"
+ rescue Exception => e
+ flash[:notice] = e.message
+ end
+ #END_HIGHLIGHT
+
+ respond_to do |format|
+ format.html { redirect_to(users_url) }
+ format.xml { head :ok }
+ end
+ #END:delete_user
+ end
+end
2  app/helpers/admin_helper.rb
@@ -0,0 +1,2 @@
+module AdminHelper
+end
3  app/helpers/application_helper.rb
@@ -0,0 +1,3 @@
+# Methods added to this helper will be available to all templates in the application.
+module ApplicationHelper
+end
2  app/helpers/info_helper.rb
@@ -0,0 +1,2 @@
+module InfoHelper
+end
2  app/helpers/line_items_helper.rb
@@ -0,0 +1,2 @@
+module LineItemsHelper
+end
2  app/helpers/orders_helper.rb
@@ -0,0 +1,2 @@
+module OrdersHelper
+end
2  app/helpers/products_helper.rb
@@ -0,0 +1,2 @@
+module ProductsHelper
+end
8 app/helpers/store_helper.rb
@@ -0,0 +1,8 @@
+module StoreHelper
+ def hidden_div_if(condition, attributes = {}, &block)
+ if condition
+ attributes["style"] = "display: none"
+ end
+ content_tag("div", attributes, &block)
+ end
+end
2  app/helpers/users_helper.rb
@@ -0,0 +1,2 @@
+module UsersHelper
+end
32 app/models/cart.rb
@@ -0,0 +1,32 @@
+class Cart
+ attr_reader :items # <wtf linkend="wtf.attr.accessor">attr_reader</wtf>
+
+ def initialize
+ @items = []
+ end
+
+ #START:add_product
+ def add_product(product)
+ current_item = @items.find {|item| item.product == product}
+ if current_item
+ current_item.increment_quantity
+ else
+ current_item = CartItem.new(product)
+ @items << current_item
+ end
+ current_item
+ end
+ #END:add_product
+
+ #START:total_price
+ def total_price
+ @items.sum { |item| item.price }
+ end
+ #END:total_price
+
+ #START:total_items
+ def total_items
+ @items.sum { |item| item.quantity }
+ end
+ #END:total_items
+end
21 app/models/cart_item.rb
@@ -0,0 +1,21 @@
+class CartItem
+
+ attr_reader :product, :quantity
+
+ def initialize(product)
+ @product = product
+ @quantity = 1
+ end
+
+ def increment_quantity
+ @quantity += 1
+ end
+
+ def title
+ @product.title
+ end
+
+ def price
+ @product.price * @quantity
+ end
+end
17 app/models/line_item.rb
@@ -0,0 +1,17 @@
+#START:belongs_to
+class LineItem < ActiveRecord::Base
+ belongs_to :order
+ belongs_to :product
+#END:belongs_to
+
+ def self.from_cart_item(cart_item)
+ li = self.new
+ li.product = cart_item.product
+ li.quantity = cart_item.quantity
+ li.total_price = cart_item.price
+ li
+ end
+
+#START:belongs_to
+end
+#END:belongs_to
39 app/models/order.rb
@@ -0,0 +1,39 @@
+#START:has_many
+#START:select
+#START:validate
+class Order < ActiveRecord::Base
+ #END:has_many
+ PAYMENT_TYPES = [
+ # Displayed stored in db
+ [ "Check", "check" ],
+ [ "Credit card", "cc" ],
+ [ "Purchase order", "po" ]
+ ]
+
+#END:validate
+ # ...
+ #END:select
+ #START:validate
+ validates_presence_of :name, :address, :email, :pay_type
+ validates_inclusion_of :pay_type, :in =>
+ PAYMENT_TYPES.map {|disp, value| value}
+
+ # ...
+ #END:validate
+
+
+ #START:has_many
+ has_many :line_items
+ #END:has_many
+
+ #START:add_line_items_from_cart
+ def add_line_items_from_cart(cart)
+ cart.items.each do |item|
+ li = LineItem.from_cart_item(item)
+ line_items << li
+ end
+ end
+ #END:add_line_items_from_cart
+#START:has_many
+end
+#END:has_many
48 app/models/product.rb
@@ -0,0 +1,48 @@
+#START:salable
+#START:has_many
+class Product < ActiveRecord::Base
+ #START_HIGHLIGHT
+ has_many :orders, :through => :line_items
+ #END_HIGHLIGHT
+ has_many :line_items
+ # ...
+#END:has_many
+
+ def self.find_products_for_sale
+ find(:all, :order => "title")
+ end
+
+ # validation stuff...
+#END:salable
+
+
+#START:validation
+#START:val1
+ validates_presence_of :title, :description, :image_url
+#END:val1
+#START:val2
+ validates_numericality_of :price
+#END:val2
+#START:val2a
+ validate :price_must_be_at_least_a_cent
+#END:val2a
+#START:val3
+ validates_uniqueness_of :title
+#END:val3
+#START:val4
+ validates_format_of :image_url,
+ :with => %r{\.(gif|jpg|png)$}i,
+ :message => 'must be a URL for GIF, JPG ' +
+ 'or PNG image.'
+#END:val4
+#START:val2a
+
+protected
+ def price_must_be_at_least_a_cent
+ errors.add(:price, 'should be at least 0.01') if price.nil? ||
+ price < 0.01
+ end
+#END:val2a
+#END:validation
+
+end
72 app/models/user.rb
@@ -0,0 +1,72 @@
+require 'digest/sha1'
+
+#START:validate
+class User < ActiveRecord::Base
+
+ validates_presence_of :name
+ validates_uniqueness_of :name
+
+ attr_accessor :password_confirmation
+ validates_confirmation_of :password
+
+ validate :password_non_blank
+
+#END:validate
+ #START:login
+ def self.authenticate(name, password)
+ user = self.find_by_name(name)
+ if user
+ expected_password = encrypted_password(password, user.salt)
+ if user.hashed_password != expected_password
+ user = nil
+ end
+ end
+ user
+ end
+ #END:login
+
+ # 'password' is a virtual attribute
+ #START:accessors
+ def password
+ @password
+ end
+
+ def password=(pwd)
+ @password = pwd
+ return if pwd.blank?
+ create_new_salt
+ self.hashed_password = User.encrypted_password(self.password, self.salt)
+ end
+ #END:accessors
+
+#START:validate
+ #START:after_destroy
+ def after_destroy
+ if User.count.zero?
+ raise "Can't delete last user"
+ end
+ end
+ #END:after_destroy
+
+private
+
+ def password_non_blank
+ errors.add(:password, "Missing password") if hashed_password.blank?
+ end
+#END:validate
+
+ #START:create_new_salt
+ def create_new_salt
+ self.salt = self.object_id.to_s + rand.to_s
+ end
+ #END:create_new_salt
+
+ #START:encrypted_password
+ def self.encrypted_password(password, salt)
+ string_to_hash = password + "wibble" + salt
+ Digest::SHA1.hexdigest(string_to_hash)
+ end
+ #END:encrypted_password
+#START:validate
+end
+#END:validate
4 app/views/admin/index.html.erb
@@ -0,0 +1,4 @@
+<h1>Welcome</h1>
+
+It's <%= Time.now %>
+We have <%= pluralize(@total_orders, "order") %>.
21 app/views/admin/login.html.erb
@@ -0,0 +1,21 @@
+<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>
2  app/views/admin/logout.html.erb
@@ -0,0 +1,2 @@
+<h1>Admin#logout</h1>
+<p>Find me in app/views/admin/logout.html.erb</p>
39 app/views/info/who_bought.atom.builder
@@ -0,0 +1,39 @@
+atom_feed do |feed|
+ feed.title "Who bought #{@product.title}"
+ feed.updated @orders.first.created_at
+
+ for order in @orders
+ feed.entry(order) do |entry|
+ entry.title "Order #{order.id}"
+ entry.summary :type => 'xhtml' do |xhtml|
+ xhtml.p "Shipped to #{order.address}"
+
+ xhtml.table do
+ xhtml.tr do
+ xhtml.th 'Product'
+ xhtml.th 'Quantity'
+ xhtml.th 'Total Price'
+ end
+ for item in order.line_items
+ xhtml.tr do
+ xhtml.td item.product.title
+ xhtml.td item.quantity
+ xhtml.td number_to_currency item.total_price
+ end
+ end
+ xhtml.tr do
+ xhtml.th 'total', :colspan => 2
+ xhtml.th number_to_currency \
+ order.line_items.map(&:total_price).sum
+ end
+ end
+
+ xhtml.p "Paid by #{order.pay_type}"
+ end
+ entry.author do |author|
+ entry.name order.name
+ entry.email order.email
+ end
+ end
+ end
+end
9 app/views/info/who_bought.html.erb
@@ -0,0 +1,9 @@
+<h3>People Who Bought <%= @product.title %></h3>
+
+<ul>
+ <% for order in @orders -%>
+ <li>
+ <%= mail_to order.email, order.name %>
+ </li>
+ <% end -%>
+</ul>
8 app/views/info/who_bought.xml.builder
@@ -0,0 +1,8 @@
+xml.order_list(:for_product => @product.title) do
+ for o in @orders
+ xml.order do
+ xml.name(o.name)
+ xml.email(o.email)
+ end
+ end
+end
17 app/views/layouts/line_items.html.erb
@@ -0,0 +1,17 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <title>LineItems: <%= controller.action_name %></title>
+ <%= stylesheet_link_tag 'scaffold' %>
+</head>
+<body>
+
+<p style="color: green"><%= flash[:notice] %></p>
+
+<%= yield %>
+
+</body>
+</html>
70 app/views/layouts/store.html.erb
@@ -0,0 +1,70 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- START:jit -->
+<html>
+<head>
+ <title>Pragprog Books Online Store</title>
+<!-- START:stylesheet -->
+ <%= stylesheet_link_tag "depot", :media => "all" %>
+<!-- END:stylesheet -->
+ <%= javascript_include_tag :defaults %>
+</head>
+<!-- END:jit -->
+<body id="store">
+ <div id="banner">
+ <!-- START:i18n -->
+ <% form_tag '', :method => 'GET', :class => 'locale' do %>
+ <%= select_tag 'locale', options_for_select(LANGUAGES, I18n.locale),
+ :onchange => 'this.form.submit()' %>
+ <%= submit_tag 'submit' %>
+ <%= javascript_tag "$$('.locale input').each(Element.hide)" %>
+ <% end %>
+ <!-- END:i18n -->
+ <%= image_tag("logo.png") %>
+<!-- START_HIGHLIGHT -->
+ <%= @page_title || I18n.t('layout.title') %>
+<!-- END_HIGHLIGHT -->
+ </div>
+ <div id="columns">
+ <div id="side">
+ <!-- START:hidden_div -->
+ <% if @cart %>
+ <% hidden_div_if(@cart.items.empty?, :id => "cart") do %>
+ <%= render(:partial => "cart", :object => @cart) %>
+ <% end %>
+ <% end %>
+ <!-- END:hidden_div -->
+
+<!-- START_HIGHLIGHT -->
+ <a href="http://www...."><%= I18n.t 'layout.side.home' %></a><br />
+<!-- END_HIGHLIGHT -->
+<!-- START_HIGHLIGHT -->
+ <a href="http://www..../faq"><%= I18n.t 'layout.side.questions' %></a><br />
+<!-- END_HIGHLIGHT -->
+<!-- START_HIGHLIGHT -->
+ <a href="http://www..../news"><%= I18n.t 'layout.side.news' %></a><br />
+<!-- END_HIGHLIGHT -->
+<!-- START_HIGHLIGHT -->
+ <a href="http://www..../contact"><%= I18n.t 'layout.side.contact' %></a><br />
+<!-- END_HIGHLIGHT -->
+ <% if session[:user_id] %>
+ <br />
+ <%= link_to 'Orders', :controller => 'orders' %><br />
+ <%= link_to 'Products', :controller => 'products' %><br />
+ <%= link_to 'Users', :controller => 'users' %><br />
+ <br />
+ <%= link_to 'Logout', :controller => 'admin', :action => 'logout' %>
+ <% end %>
+ </div>
+ <div id="main">
+ <!-- START:flash -->
+ <% if flash[:notice] -%>
+ <div id="notice"><%= flash[:notice] %></div>
+ <% end -%>
+ <!-- END:flash -->
+
+ <%= yield :layout %>
+ </div>
+ </div>
+</body>
+</html>
28 app/views/line_items/edit.html.erb
@@ -0,0 +1,28 @@
+<h1>Editing line_item</h1>
+
+<% form_for(@line_item) do |f| %>
+ <%= f.error_messages %>
+
+ <p>
+ <%= f.label :product_id %><br />
+ <%= f.text_field :product_id %>
+ </p>
+ <p>
+ <%= f.label :order_id %><br />
+ <%= f.text_field :order_id %>
+ </p>
+ <p>
+ <%= f.label :quantity %><br />
+ <%= f.text_field :quantity %>
+ </p>
+ <p>
+ <%= f.label :total_price %><br />
+ <%= f.text_field :total_price %>
+ </p>
+ <p>
+ <%= f.submit 'Update' %>
+ </p>
+<% end %>
+
+<%= link_to 'Show', @line_item %> |
+<%= link_to 'Back', line_items_path %>
26 app/views/line_items/index.html.erb
@@ -0,0 +1,26 @@
+<h1>Listing line_items</h1>
+
+<table>
+ <tr>
+ <th>Product</th>
+ <th>Order</th>
+ <th>Quantity</th>
+ <th>Total price</th>
+ </tr>
+
+<% @line_items.each do |line_item| %>
+ <tr>
+ <td><%=h line_item.product_id %></td>
+ <td><%=h line_item.order_id %></td>
+ <td><%=h line_item.quantity %></td>
+ <td><%=h line_item.total_price %></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 %>
27 app/views/line_items/new.html.erb
@@ -0,0 +1,27 @@
+<h1>New line_item</h1>
+
+<% form_for(@line_item) do |f| %>
+ <%= f.error_messages %>
+
+ <p>
+ <%= f.label :product_id %><br />
+ <%= f.text_field :product_id %>
+ </p>
+ <p>
+ <%= f.label :order_id %><br />
+ <%= f.text_field :order_id %>
+ </p>
+ <p>
+ <%= f.label :quantity %><br />
+ <%= f.text_field :quantity %>
+ </p>
+ <p>
+ <%= f.label :total_price %><br />
+ <%= f.text_field :total_price %>
+ </p>
+ <p>
+ <%= f.submit 'Create' %>
+ </p>
+<% end %>
+
+<%= link_to 'Back', line_items_path %>
23 app/views/line_items/show.html.erb
@@ -0,0 +1,23 @@
+<p>
+ <b>Product:</b>
+ <%=h @line_item.product_id %>
+</p>
+
+<p>
+ <b>Order:</b>
+ <%=h @line_item.order_id %>
+</p>
+
+<p>
+ <b>Quantity:</b>
+ <%=h @line_item.quantity %>
+</p>
+
+<p>
+ <b>Total price:</b>
+ <%=h @line_item.total_price %>
+</p>
+
+
+<%= link_to 'Edit', edit_line_item_path(@line_item) %> |
+<%= link_to 'Back', line_items_path %>
28 app/views/orders/edit.html.erb
@@ -0,0 +1,28 @@
+<h1>Editing order</h1>
+
+<% form_for(@order) do |f| %>
+ <%= f.error_messages %>
+
+ <p>
+ <%= f.label :name %><br />
+ <%= f.text_field :name %>
+ </p>
+ <p>
+ <%= f.label :address %><br />
+ <%= f.text_area :address %>
+ </p>
+ <p>
+ <%= f.label :email %><br />
+ <%= f.text_field :email %>
+ </p>
+ <p>
+ <%= f.label :pay_type %><br />
+ <%= f.text_field :pay_type %>
+ </p>
+ <p>
+ <%= f.submit 'Update' %>
+ </p>
+<% end %>
+
+<%= link_to 'Show', @order %> |
+<%= link_to 'Back', orders_path %>
26 app/views/orders/index.html.erb
@@ -0,0 +1,26 @@
+<h1>Listing orders</h1>
+
+<table>
+ <tr>
+ <th>Name</th>
+ <th>Address</th>
+ <th>Email</th>
+ <th>Pay type</th>
+ </tr>
+
+<% @orders.each do |order| %>
+ <tr>
+ <td><%=h order.name %></td>
+ <td><%=h order.address %></td>
+ <td><%=h order.email %></td>
+ <td><%=h 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 %>
27 app/views/orders/new.html.erb
@@ -0,0 +1,27 @@
+<h1>New order</h1>
+
+<% form_for(@order) do |f| %>
+ <%= f.error_messages %>
+
+ <p>
+ <%= f.label :name %><br />
+ <%= f.text_field :name %>
+ </p>
+ <p>
+ <%= f.label :address %><br />
+ <%= f.text_area :address %>
+ </p>
+ <p>
+ <%= f.label :email %><br />
+ <%= f.text_field :email %>
+ </p>
+ <p>
+ <%= f.label :pay_type %><br />
+ <%= f.text_field :pay_type %>
+ </p>
+ <p>
+ <%= f.submit 'Create' %>
+ </p>
+<% end %>
+
+<%= link_to 'Back', orders_path %>
23 app/views/orders/show.html.erb
@@ -0,0 +1,23 @@
+<p>
+ <b>Name:</b>
+ <%=h @order.name %>
+</p>
+
+<p>
+ <b>Address:</b>
+ <%=h @order.address %>
+</p>
+
+<p>
+ <b>Email:</b>
+ <%=h @order.email %>
+</p>
+
+<p>
+ <b>Pay type:</b>
+ <%=h @order.pay_type %>
+</p>
+
+
+<%= link_to 'Edit', edit_order_path(@order) %> |
+<%= link_to 'Back', orders_path %>
31 app/views/products/edit.html.erb
@@ -0,0 +1,31 @@
+<h1>Editing product</h1>
+
+<% form_for(@product) do |f| %>
+ <%= f.error_messages %>
+
+ <p>
+ <%= f.label :title %><br />
+ <%= f.text_field :title %>
+ </p>
+ <p>
+ <%= f.label :description %><br />
+ <%= f.text_area :description %>
+ </p>
+ <p>
+ <%= f.label :image_url %><br />
+ <%= f.text_field :image_url %>
+ </p>
+ <!-- START_HIGHLIGHT -->
+ <p>
+ <%= f.label :price %><br />
+ <%= f.text_field :price %>
+ </p>
+ <!-- END_HIGHLIGHT -->
+
+ <p>
+ <%= f.submit 'Update' %>
+ </p>
+<% end %>
+
+<%= link_to 'Show', @product %> |
+<%= link_to 'Back', products_path %>
34 app/views/products/index.html.erb
@@ -0,0 +1,34 @@
+<div id="product-list">
+ <h1>Listing products</h1>
+
+ <table>
+ <% for product in @products %>
+ <tr class="<%= cycle('list-line-odd', 'list-line-even') %>">
+
+ <td>
+ <%= image_tag product.image_url, :class => 'list-image' %>
+ </td>
+
+ <td class="list-description">
+ <dl>
+ <dt><%=h product.title %></dt>
+ <dd><%=h truncate(product.description.gsub(/<.*?>/,''),
+ :length => 80) %></dd>
+ </dl>
+ </td>
+
+ <td class="list-actions">
+ <%= link_to 'Show', product %><br/>
+ <%= link_to 'Edit', edit_product_path(product) %><br/>
+ <%= link_to 'Destroy', product,
+ :confirm => 'Are you sure?',
+ :method => :delete %>
+ </td>
+ </tr>
+ <% end %>
+ </table>
+</div>
+
+<br />
+
+<%= link_to 'New product', new_product_path %>
30 app/views/products/new.html.erb
@@ -0,0 +1,30 @@
+<h1>New product</h1>
+
+<% form_for(@product) do |f| %>
+ <%= f.error_messages %>
+
+ <p>
+ <%= f.label :title %><br />
+ <%= f.text_field :title %>
+ </p>
+ <p>
+ <%= f.label :description %><br />
+ <%= f.text_area :description, :rows => 6 %>
+ </p>
+ <p>
+ <%= f.label :image_url %><br />
+ <%= f.text_field :image_url %>
+ </p>
+ <!-- START_HIGHLIGHT -->
+ <p>
+ <%= f.label :price %><br />
+ <%= f.text_field :price %>
+ </p>
+ <!-- END_HIGHLIGHT -->
+
+ <p>
+ <%= f.submit 'Create' %>
+ </p>
+<% end %>
+
+<%= link_to 'Back', products_path %>
24 app/views/products/show.html.erb
@@ -0,0 +1,24 @@
+<p>
+ <b>Title:</b>
+ <%=h @product.title %>
+</p>
+
+<p>
+ <b>Description:</b>
+<!-- START_HIGHLIGHT -->
+ <%= @product.description %>
+<!-- END_HIGHLIGHT -->
+</p>
+
+<p>
+ <b>Image url:</b>
+ <%=h @product.image_url %>
+</p>
+
+<p>
+ <b>Price:</b>
+ <%=h @product.price %>
+</p>
+
+<%= link_to 'Edit', edit_product_path(@product) %> |
+<%= link_to 'Back', products_path %>
19 app/views/store/_cart.html.erb
@@ -0,0 +1,19 @@
+<!-- START_HIGHLIGHT -->
+<div class="cart-title"><%= I18n.t 'layout.cart.title' %></div>
+<!-- END_HIGHLIGHT -->
+<table>
+ <%= render(:partial => "cart_item", :collection => cart.items) %>
+
+ <tr class="total-line">
+ <td colspan="2">Total</td>
+ <td class="total-cell"><%= number_to_currency(cart.total_price) %></td>
+ </tr>
+
+</table>
+
+<!-- START_HIGHLIGHT -->
+<%= button_to I18n.t('layout.cart.button.checkout'), :action => 'checkout' %>
+<!-- END_HIGHLIGHT -->
+<!-- START_HIGHLIGHT -->
+<%= button_to I18n.t('layout.cart.button.empty'), :action => :empty_cart %>
+<!-- END_HIGHLIGHT -->
11 app/views/store/_cart_item.html.erb
@@ -0,0 +1,11 @@
+<!-- START_HIGHLIGHT -->
+<% if cart_item == @current_item %>
+ <tr id="current_item">
+<% else %>
+ <tr>
+<% end %>
+<!-- #END_HIGHLIGHT -->
+ <td><%= cart_item.quantity %>&times;</td>
+ <td><%=h cart_item.title %></td>
+ <td class="item-price"><%= number_to_currency(cart_item.price) %></td>
+</tr>
11 app/views/store/add_to_cart.js.rjs
@@ -0,0 +1,11 @@
+#START_HIGHLIGHT
+page.select("div#notice").each { |div| div.hide }
+#END_HIGHLIGHT
+
+page.replace_html("cart", :partial => "cart", :object => @cart)
+
+page[:cart].visual_effect :blind_down if @cart.total_items == 1
+
+page[:current_item].visual_effect :highlight,
+ :startcolor => "#88ff88",
+ :endcolor => "#114411"
50 app/views/store/checkout.html.erb
@@ -0,0 +1,50 @@
+<div class="depot-form">
+
+ <%= error_messages_for 'order' %>
+
+ <% form_for :order, :url => { :action => :save_order } do |form| %>
+ <fieldset>
+<!-- START_HIGHLIGHT -->
+ <legend><%= I18n.t 'checkout.legend' %></legend>
+<!-- END_HIGHLIGHT -->
+
+ <div>
+<!-- START_HIGHLIGHT -->
+ <%= form.label :name, I18n.t('checkout.name') + ":" %>
+<!-- END_HIGHLIGHT -->
+ <%= form.text_field :name, :size => 40 %>
+ </div>
+
+ <div>
+<!-- START_HIGHLIGHT -->
+ <%= form.label :address, I18n.t('checkout.address') + ":" %>
+<!-- END_HIGHLIGHT -->
+ <%= form.text_area :address, :rows => 3, :cols => 40 %>
+ </div>
+
+ <div>
+<!-- START_HIGHLIGHT -->
+ <%= form.label :email, I18n.t('checkout.email') + ":" %>
+<!-- END_HIGHLIGHT -->
+ <%= form.text_field :email, :size => 40 %>
+ </div>
+
+ <div>
+<!-- START_HIGHLIGHT -->
+ <%= form.label :pay_type, I18n.t('checkout.pay_type') + ":" %>
+<!-- END_HIGHLIGHT -->
+ <%=
+ form.select :pay_type,
+ Order::PAYMENT_TYPES,
+# START_HIGHLIGHT
+ :prompt => I18n.t('checkout.pay_prompt')
+# END_HIGHLIGHT
+ %>
+ </div>
+
+<!-- START_HIGHLIGHT -->
+ <%= submit_tag I18n.t('checkout.submit'), :class => "submit" %>
+<!-- END_HIGHLIGHT -->
+ </fieldset>
+ <% end %>
+</div>
21 app/views/store/index.html.erb
@@ -0,0 +1,21 @@
+<!-- START_HIGHLIGHT -->
+<h1><%= I18n.t 'main.title' %></h1>
+<!-- END_HIGHLIGHT -->
+
+<% for product in @products -%>
+ <div class="entry">
+ <%= image_tag(product.image_url) %>
+ <h3><%=h product.title %></h3>
+ <%= product.description %>
+ <div class="price-line">
+ <span class="price"><%= number_to_currency(product.price) %></span>
+ <!-- START:form_remote_tag -->
+ <% form_remote_tag :url => {:action => 'add_to_cart', :id => product} do %>
+<!-- START_HIGHLIGHT -->
+ <%= submit_tag I18n.t('main.button.add') %>
+<!-- END_HIGHLIGHT -->
+ <% end %>
+ <!-- END:form_remote_tag -->
+ </div>
+ </div>
+<% end %>
24 app/views/users/edit.html.erb
@@ -0,0 +1,24 @@
+<h1>Editing user</h1>
+
+<% form_for(@user) do |f| %>
+ <%= f.error_messages %>
+
+ <p>
+ <%= f.label :name %><br />
+ <%= f.text_field :name %>
+ </p>
+ <p>
+ <%= f.label :hashed_password %><br />
+ <%= f.text_field :hashed_password %>
+ </p>
+ <p>
+ <%= f.label :salt %><br />
+ <%= f.text_field :salt %>
+ </p>
+ <p>
+ <%= f.submit 'Update' %>
+ </p>
+<% end %>
+
+<%= link_to 'Show', @user %> |
+<%= link_to 'Back', users_path %>
21 app/views/users/index.html.erb
@@ -0,0 +1,21 @@
+<h1>Listing users</h1>
+
+<table>
+ <tr>
+ <th>Name</th>
+ </tr>
+
+<% @users.each do |user| %>
+ <tr>
+ <td><%=h 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 %>
31 app/views/users/new.html.erb
@@ -0,0 +1,31 @@
+<div class="depot-form">
+
+<% form_for(@user) do |f| %>
+ <%= f.error_messages %>
+
+ <fieldset>
+ <legend>Enter User Details</legend>
+
+ <div>
+ <%= f.label :name %>:
+ <%= f.text_field :name, :size => 40 %>
+ </div>
+
+ <div>
+ <%= f.label :password, 'Password' %>:
+ <%= f.password_field :password, :size => 40 %>
+ </div>
+
+ <div>
+ <%= f.label :password_confirmation, 'Confirm' %>:
+ <%= f.password_field :password_confirmation, :size => 40 %>
+ </div>
+
+ <div>
+ <%= f.submit "Add User", :class => "submit" %>
+ </div>
+
+ </fieldset>
+<% end %>
+
+</div>
18 app/views/users/show.html.erb
@@ -0,0 +1,18 @@
+<p>
+ <b>Name:</b>
+ <%=h @user.name %>
+</p>
+
+<p>
+ <b>Hashed password:</b>
+ <%=h @user.hashed_password %>
+</p>
+
+<p>
+ <b>Salt:</b>
+ <%=h @user.salt %>
+</p>
+
+
+<%= link_to 'Edit', edit_user_path(@user) %> |
+<%= link_to 'Back', users_path %>
110 config/boot.rb
@@ -0,0 +1,110 @@
+# Don't change this file!
+# Configure your app in config/environment.rb and config/environments/*.rb
+
+RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
+
+module Rails
+ class << self
+ def boot!
+ unless booted?
+ preinitialize
+ pick_boot.run
+ end
+ end
+
+ def booted?
+ defined? Rails::Initializer
+ end
+
+ def pick_boot
+ (vendor_rails? ? VendorBoot : GemBoot).new
+ end
+
+ def vendor_rails?
+ File.exist?("#{RAILS_ROOT}/vendor/rails")
+ end
+
+ def preinitialize
+ load(preinitializer_path) if File.exist?(preinitializer_path)
+ end
+
+ def preinitializer_path
+ "#{RAILS_ROOT}/config/preinitializer.rb"
+ end
+ end
+
+ class Boot
+ def run
+ load_initializer
+ Rails::Initializer.run(:set_load_path)
+ end
+ end
+
+ class VendorBoot < Boot
+ def load_initializer
+ require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
+ Rails::Initializer.run(:install_gem_spec_stubs)
+ Rails::GemDependency.add_frozen_gem_path
+ end
+ end
+
+ class GemBoot < Boot
+ def load_initializer
+ self.class.load_rubygems
+ load_rails_gem
+ require 'initializer'
+ end
+
+ def load_rails_gem
+ if version = self.class.gem_version
+ gem 'rails', version
+ else
+ gem 'rails'
+ end
+ rescue Gem::LoadError => load_error
+ $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
+ exit 1
+ end
+
+ class << self
+ def rubygems_version
+ Gem::RubyGemsVersion rescue nil
+ end
+
+ def gem_version
+ if defined? RAILS_GEM_VERSION
+ RAILS_GEM_VERSION
+ elsif ENV.include?('RAILS_GEM_VERSION')
+ ENV['RAILS_GEM_VERSION']
+ else
+ parse_gem_version(read_environment_rb)
+ end
+ end
+
+ def load_rubygems
+ require 'rubygems'
+ min_version = '1.3.1'
+ unless rubygems_version >= min_version
+ $stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
+ exit 1
+ end
+
+ rescue LoadError
+ $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
+ exit 1
+ end
+
+ def parse_gem_version(text)
+ $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
+ end
+
+ private
+ def read_environment_rb
+ File.read("#{RAILS_ROOT}/config/environment.rb")
+ end
+ end
+ end
+end
+
+# All that for this:
+Rails.boot!
22 config/database.sample.yml
@@ -0,0 +1,22 @@
+# 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
41 config/environment.rb
@@ -0,0 +1,41 @@
+# Be sure to restart your server when you modify this file
+
+# Specifies gem version of Rails to use when vendor/rails is not present
+RAILS_GEM_VERSION = '3.0.pre' unless defined? RAILS_GEM_VERSION
+
+# Bootstrap the Rails environment, frameworks, and default configuration
+require File.join(File.dirname(__FILE__), 'boot')
+
+Rails::Initializer.run do |config|
+ # Settings in config/environments/* take precedence over those specified here.
+ # Application configuration should go into files in config/initializers
+ # -- all .rb files in that directory are automatically loaded.
+
+ # Add additional load paths for your own custom dirs
+ # config.load_paths += %W( #{RAILS_ROOT}/extras )
+
+ # Specify gems that this application depends on and have them installed with rake gems:install
+ # config.gem "bj"
+ # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
+ # config.gem "sqlite3-ruby", :lib => "sqlite3"
+ # config.gem "aws-s3", :lib => "aws/s3"
+
+ # Only load the plugins named here, in the order given (default is alphabetical).
+ # :all can be used as a placeholder for all plugins not explicitly named
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
+
+ # Skip frameworks you're not going to use. To use Rails without a database,
+ # you must remove the Active Record framework.
+ # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
+
+ # Activate observers that should always be running
+ # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
+
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
+ # Run "rake -D time" for a list of tasks for finding time zone names.
+ config.time_zone = 'UTC'
+
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
+ # config.i18n.default_locale = :de
+end