Skip to content
This repository
Browse code

adding episode 211

  • Loading branch information...
commit de8154d3ec481d21ab6dadb2b17ebaebef80c01b 1 parent 59dfd90
Ryan Bates authored April 26, 2010

Showing 59 changed files with 9,113 additions and 0 deletions. Show diff stats Hide diff stats

  1. 12  episode-211/README
  2. 4  episode-211/store/.gitignore
  3. 26  episode-211/store/Gemfile
  4. 244  episode-211/store/README
  5. 10  episode-211/store/Rakefile
  6. 4  episode-211/store/app/controllers/application_controller.rb
  7. 83  episode-211/store/app/controllers/users_controller.rb
  8. 5  episode-211/store/app/helpers/application_helper.rb
  9. 2  episode-211/store/app/helpers/users_helper.rb
  10. 3  episode-211/store/app/models/user.rb
  11. 14  episode-211/store/app/views/layouts/application.html.erb
  12. 10  episode-211/store/app/views/shared/_error_messages.html.erb
  13. 15  episode-211/store/app/views/users/_form.html.erb
  14. 6  episode-211/store/app/views/users/edit.html.erb
  15. 25  episode-211/store/app/views/users/index.html.erb
  16. 5  episode-211/store/app/views/users/new.html.erb
  17. 15  episode-211/store/app/views/users/show.html.erb
  18. 4  episode-211/store/config.ru
  19. 46  episode-211/store/config/application.rb
  20. 6  episode-211/store/config/boot.rb
  21. 22  episode-211/store/config/database.yml
  22. 5  episode-211/store/config/environment.rb
  23. 19  episode-211/store/config/environments/development.rb
  24. 42  episode-211/store/config/environments/production.rb
  25. 32  episode-211/store/config/environments/test.rb
  26. 7  episode-211/store/config/initializers/backtrace_silencers.rb
  27. 10  episode-211/store/config/initializers/inflections.rb
  28. 5  episode-211/store/config/initializers/mime_types.rb
  29. 7  episode-211/store/config/initializers/secret_token.rb
  30. 8  episode-211/store/config/initializers/session_store.rb
  31. 5  episode-211/store/config/locales/en.yml
  32. 61  episode-211/store/config/routes.rb
  33. 14  episode-211/store/db/migrate/20100426050559_create_users.rb
  34. 21  episode-211/store/db/schema.rb
  35. 7  episode-211/store/db/seeds.rb
  36. 2  episode-211/store/doc/README_FOR_APP
  37. 7  episode-211/store/lib/email_format_validator.rb
  38. 26  episode-211/store/public/404.html
  39. 26  episode-211/store/public/422.html
  40. 26  episode-211/store/public/500.html
  41. 0  episode-211/store/public/favicon.ico
  42. 2  episode-211/store/public/javascripts/application.js
  43. 965  episode-211/store/public/javascripts/controls.js
  44. 974  episode-211/store/public/javascripts/dragdrop.js
  45. 1,123  episode-211/store/public/javascripts/effects.js
  46. 4,874  episode-211/store/public/javascripts/prototype.js
  47. 118  episode-211/store/public/javascripts/rails.js
  48. 5  episode-211/store/public/robots.txt
  49. 0  episode-211/store/public/stylesheets/.gitkeep
  50. 60  episode-211/store/public/stylesheets/scaffold.css
  51. 9  episode-211/store/script/rails
  52. 9  episode-211/store/test/fixtures/users.yml
  53. 49  episode-211/store/test/functional/users_controller_test.rb
  54. 9  episode-211/store/test/performance/browsing_test.rb
  55. 13  episode-211/store/test/test_helper.rb
  56. 4  episode-211/store/test/unit/helpers/users_helper_test.rb
  57. 8  episode-211/store/test/unit/user_test.rb
  58. 0  episode-211/store/vendor/plugins/.gitkeep
  59. 0  tasks/.gitkeep b/episode-211/store/lib/tasks/.gitkeep
12  episode-211/README
... ...
@@ -0,0 +1,12 @@
  1
+Railscasts Episode #211: Validations in Rails 3
  2
+
  3
+http://railscasts.com/episodes/211
  4
+
  5
+Commands
  6
+
  7
+  gem install rails --pre
  8
+  gem cleanup
  9
+  rails store
  10
+  cd store
  11
+  rails g scaffold user name:string email:string
  12
+  rake db:migrate
4  episode-211/store/.gitignore
... ...
@@ -0,0 +1,4 @@
  1
+.bundle
  2
+db/*.sqlite3
  3
+log/*.log
  4
+tmp/**/*
26  episode-211/store/Gemfile
... ...
@@ -0,0 +1,26 @@
  1
+source 'http://rubygems.org'
  2
+
  3
+gem 'rails', '3.0.0.beta3'
  4
+
  5
+# Bundle edge Rails instead:
  6
+# gem 'rails', :git => 'git://github.com/rails/rails.git'
  7
+
  8
+gem 'sqlite3-ruby', :require => 'sqlite3'
  9
+
  10
+# Use unicorn as the web server
  11
+# gem 'unicorn'
  12
+
  13
+# Deploy with Capistrano
  14
+# gem 'capistrano'
  15
+
  16
+# Bundle the extra gems:
  17
+# gem 'bj'
  18
+# gem 'nokogiri', '1.4.1'
  19
+# gem 'sqlite3-ruby', :require => 'sqlite3'
  20
+# gem 'aws-s3', :require => 'aws/s3'
  21
+
  22
+# Bundle gems for certain environments:
  23
+# gem 'rspec', :group => :test
  24
+# group :test do
  25
+#   gem 'webrat'
  26
+# end
244  episode-211/store/README
... ...
@@ -0,0 +1,244 @@
  1
+== Welcome to Rails
  2
+
  3
+Rails is a web-application framework that includes everything needed to create 
  4
+database-backed web applications according to the Model-View-Control pattern. 
  5
+
  6
+This pattern splits the view (also called the presentation) into "dumb" templates
  7
+that are primarily responsible for inserting pre-built data in between HTML tags.
  8
+The model contains the "smart" domain objects (such as Account, Product, Person,
  9
+Post) that holds all the business logic and knows how to persist themselves to
  10
+a database. The controller handles the incoming requests (such as Save New Account,
  11
+Update Product, Show Post) by manipulating the model and directing data to the view.
  12
+
  13
+In Rails, the model is handled by what's called an object-relational mapping
  14
+layer entitled Active Record. This layer allows you to present the data from
  15
+database rows as objects and embellish these data objects with business logic
  16
+methods. You can read more about Active Record in
  17
+link:files/vendor/rails/activerecord/README.html.
  18
+
  19
+The controller and view are handled by the Action Pack, which handles both
  20
+layers by its two parts: Action View and Action Controller. These two layers
  21
+are bundled in a single package due to their heavy interdependence. This is
  22
+unlike the relationship between the Active Record and Action Pack that is much
  23
+more separate. Each of these packages can be used independently outside of
  24
+Rails.  You can read more about Action Pack in
  25
+link:files/vendor/rails/actionpack/README.html.
  26
+
  27
+
  28
+== Getting Started
  29
+
  30
+1. At the command prompt, start a new Rails application using the <tt>rails</tt> command
  31
+   and your application name. Ex: rails myapp
  32
+2. Change directory into myapp and start the web server: <tt>rails server</tt> (run with --help for options)
  33
+3. Go to http://localhost:3000/ and get "Welcome aboard: You're riding the Rails!"
  34
+4. Follow the guidelines to start developing your application
  35
+
  36
+
  37
+== Web Servers
  38
+
  39
+By default, Rails will try to use Mongrel if it's installed when started with <tt>rails server</tt>, otherwise
  40
+Rails will use WEBrick, the webserver that ships with Ruby. But you can also use Rails
  41
+with a variety of other web servers.
  42
+
  43
+Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is
  44
+suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
  45
+getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
  46
+More info at: http://mongrel.rubyforge.org
  47
+
  48
+Say other Ruby web servers like Thin and Ebb or regular web servers like Apache or LiteSpeed or
  49
+Lighttpd or IIS. The Ruby web servers are run through Rack and the latter can either be setup to use
  50
+FCGI or proxy to a pack of Mongrels/Thin/Ebb servers.
  51
+
  52
+== Apache .htaccess example for FCGI/CGI
  53
+
  54
+# General Apache options
  55
+AddHandler fastcgi-script .fcgi
  56
+AddHandler cgi-script .cgi
  57
+Options +FollowSymLinks +ExecCGI
  58
+
  59
+# If you don't want Rails to look in certain directories,
  60
+# use the following rewrite rules so that Apache won't rewrite certain requests
  61
+# 
  62
+# Example:
  63
+#   RewriteCond %{REQUEST_URI} ^/notrails.*
  64
+#   RewriteRule .* - [L]
  65
+
  66
+# Redirect all requests not available on the filesystem to Rails
  67
+# By default the cgi dispatcher is used which is very slow
  68
+# 
  69
+# For better performance replace the dispatcher with the fastcgi one
  70
+#
  71
+# Example:
  72
+#   RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
  73
+RewriteEngine On
  74
+
  75
+# If your Rails application is accessed via an Alias directive,
  76
+# then you MUST also set the RewriteBase in this htaccess file.
  77
+#
  78
+# Example:
  79
+#   Alias /myrailsapp /path/to/myrailsapp/public
  80
+#   RewriteBase /myrailsapp
  81
+
  82
+RewriteRule ^$ index.html [QSA]
  83
+RewriteRule ^([^.]+)$ $1.html [QSA]
  84
+RewriteCond %{REQUEST_FILENAME} !-f
  85
+RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
  86
+
  87
+# In case Rails experiences terminal errors
  88
+# Instead of displaying this message you can supply a file here which will be rendered instead
  89
+# 
  90
+# Example:
  91
+#   ErrorDocument 500 /500.html
  92
+
  93
+ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
  94
+
  95
+
  96
+== Debugging Rails
  97
+
  98
+Sometimes your application goes wrong.  Fortunately there are a lot of tools that
  99
+will help you debug it and get it back on the rails.
  100
+
  101
+First area to check is the application log files.  Have "tail -f" commands running
  102
+on the server.log and development.log. Rails will automatically display debugging
  103
+and runtime information to these files. Debugging info will also be shown in the
  104
+browser on requests from 127.0.0.1.
  105
+
  106
+You can also log your own messages directly into the log file from your code using
  107
+the Ruby logger class from inside your controllers. Example:
  108
+
  109
+  class WeblogController < ActionController::Base
  110
+    def destroy
  111
+      @weblog = Weblog.find(params[:id])
  112
+      @weblog.destroy
  113
+      logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
  114
+    end
  115
+  end
  116
+
  117
+The result will be a message in your log file along the lines of:
  118
+
  119
+  Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1
  120
+
  121
+More information on how to use the logger is at http://www.ruby-doc.org/core/
  122
+
  123
+Also, Ruby documentation can be found at http://www.ruby-lang.org/ including:
  124
+
  125
+* The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/
  126
+* Learn to Program: http://pine.fm/LearnToProgram/  (a beginners guide)
  127
+
  128
+These two online (and free) books will bring you up to speed on the Ruby language
  129
+and also on programming in general.
  130
+
  131
+
  132
+== Debugger
  133
+
  134
+Debugger support is available through the debugger command when you start your Mongrel or
  135
+Webrick server with --debugger. This means that you can break out of execution at any point
  136
+in the code, investigate and change the model, AND then resume execution! 
  137
+You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'
  138
+Example:
  139
+
  140
+  class WeblogController < ActionController::Base
  141
+    def index
  142
+      @posts = Post.find(:all)
  143
+      debugger
  144
+    end
  145
+  end
  146
+
  147
+So the controller will accept the action, run the first line, then present you
  148
+with a IRB prompt in the server window. Here you can do things like:
  149
+
  150
+  >> @posts.inspect
  151
+  => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
  152
+       #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
  153
+  >> @posts.first.title = "hello from a debugger"
  154
+  => "hello from a debugger"
  155
+
  156
+...and even better is that you can examine how your runtime objects actually work:
  157
+
  158
+  >> f = @posts.first
  159
+  => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
  160
+  >> f.
  161
+  Display all 152 possibilities? (y or n)
  162
+
  163
+Finally, when you're ready to resume execution, you enter "cont"
  164
+
  165
+
  166
+== Console
  167
+
  168
+You can interact with the domain model by starting the console through <tt>rails console</tt>.
  169
+Here you'll have all parts of the application configured, just like it is when the
  170
+application is running. You can inspect domain models, change values, and save to the
  171
+database. Starting the script without arguments will launch it in the development environment.
  172
+Passing an argument will specify a different environment, like <tt>rails console production</tt>.
  173
+
  174
+To reload your controllers and models after launching the console run <tt>reload!</tt>
  175
+
  176
+== dbconsole
  177
+
  178
+You can go to the command line of your database directly through <tt>rails dbconsole</tt>.
  179
+You would be connected to the database with the credentials defined in database.yml.
  180
+Starting the script without arguments will connect you to the development database. Passing an
  181
+argument will connect you to a different database, like <tt>rails dbconsole production</tt>.
  182
+Currently works for mysql, postgresql and sqlite.
  183
+
  184
+== Description of Contents
  185
+
  186
+app
  187
+  Holds all the code that's specific to this particular application.
  188
+
  189
+app/controllers
  190
+  Holds controllers that should be named like weblogs_controller.rb for
  191
+  automated URL mapping. All controllers should descend from ApplicationController
  192
+  which itself descends from ActionController::Base.
  193
+
  194
+app/models
  195
+  Holds models that should be named like post.rb.
  196
+  Most models will descend from ActiveRecord::Base.
  197
+
  198
+app/views
  199
+  Holds the template files for the view that should be named like
  200
+  weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby
  201
+  syntax.
  202
+
  203
+app/views/layouts
  204
+  Holds the template files for layouts to be used with views. This models the common
  205
+  header/footer method of wrapping views. In your views, define a layout using the
  206
+  <tt>layout :default</tt> and create a file named default.html.erb. Inside default.html.erb,
  207
+  call <% yield %> to render the view using this layout.
  208
+
  209
+app/helpers
  210
+  Holds view helpers that should be named like weblogs_helper.rb. These are generated
  211
+  for you automatically when using rails generate for controllers. Helpers can be used to
  212
+  wrap functionality for your views into methods.
  213
+
  214
+config
  215
+  Configuration files for the Rails environment, the routing map, the database, and other dependencies.
  216
+
  217
+db
  218
+  Contains the database schema in schema.rb.  db/migrate contains all
  219
+  the sequence of Migrations for your schema.
  220
+
  221
+doc
  222
+  This directory is where your application documentation will be stored when generated
  223
+  using <tt>rake doc:app</tt>
  224
+
  225
+lib
  226
+  Application specific libraries. Basically, any kind of custom code that doesn't
  227
+  belong under controllers, models, or helpers. This directory is in the load path.
  228
+
  229
+public
  230
+  The directory available for the web server. Contains subdirectories for images, stylesheets,
  231
+  and javascripts. Also contains the dispatchers and the default HTML files. This should be
  232
+  set as the DOCUMENT_ROOT of your web server.
  233
+
  234
+script
  235
+  Helper scripts for automation and generation.
  236
+
  237
+test
  238
+  Unit and functional tests along with fixtures. When using the rails generate command, template
  239
+  test files will be generated for you and placed in this directory.
  240
+
  241
+vendor
  242
+  External libraries that the application depends on. Also includes the plugins subdirectory.
  243
+  If the app has frozen rails, those gems also go here, under vendor/rails/.
  244
+  This directory is in the load path.
10  episode-211/store/Rakefile
... ...
@@ -0,0 +1,10 @@
  1
+# Add your own tasks in files placed in lib/tasks ending in .rake,
  2
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
  3
+
  4
+require File.expand_path('../config/application', __FILE__)
  5
+
  6
+require 'rake'
  7
+require 'rake/testtask'
  8
+require 'rake/rdoctask'
  9
+
  10
+Rails::Application.load_tasks
4  episode-211/store/app/controllers/application_controller.rb
... ...
@@ -0,0 +1,4 @@
  1
+class ApplicationController < ActionController::Base
  2
+  protect_from_forgery
  3
+  layout 'application'
  4
+end
83  episode-211/store/app/controllers/users_controller.rb
... ...
@@ -0,0 +1,83 @@
  1
+class UsersController < ApplicationController
  2
+  # GET /users
  3
+  # GET /users.xml
  4
+  def index
  5
+    @users = User.all
  6
+
  7
+    respond_to do |format|
  8
+      format.html # index.html.erb
  9
+      format.xml  { render :xml => @users }
  10
+    end
  11
+  end
  12
+
  13
+  # GET /users/1
  14
+  # GET /users/1.xml
  15
+  def show
  16
+    @user = User.find(params[:id])
  17
+
  18
+    respond_to do |format|
  19
+      format.html # show.html.erb
  20
+      format.xml  { render :xml => @user }
  21
+    end
  22
+  end
  23
+
  24
+  # GET /users/new
  25
+  # GET /users/new.xml
  26
+  def new
  27
+    @user = User.new
  28
+
  29
+    respond_to do |format|
  30
+      format.html # new.html.erb
  31
+      format.xml  { render :xml => @user }
  32
+    end
  33
+  end
  34
+
  35
+  # GET /users/1/edit
  36
+  def edit
  37
+    @user = User.find(params[:id])
  38
+  end
  39
+
  40
+  # POST /users
  41
+  # POST /users.xml
  42
+  def create
  43
+    @user = User.new(params[:user])
  44
+
  45
+    respond_to do |format|
  46
+      if @user.save
  47
+        format.html { redirect_to(@user, :notice => 'User was successfully created.') }
  48
+        format.xml  { render :xml => @user, :status => :created, :location => @user }
  49
+      else
  50
+        format.html { render :action => "new" }
  51
+        format.xml  { render :xml => @user.errors, :status => :unprocessable_entity }
  52
+      end
  53
+    end
  54
+  end
  55
+
  56
+  # PUT /users/1
  57
+  # PUT /users/1.xml
  58
+  def update
  59
+    @user = User.find(params[:id])
  60
+
  61
+    respond_to do |format|
  62
+      if @user.update_attributes(params[:user])
  63
+        format.html { redirect_to(@user, :notice => 'User was successfully updated.') }
  64
+        format.xml  { head :ok }
  65
+      else
  66
+        format.html { render :action => "edit" }
  67
+        format.xml  { render :xml => @user.errors, :status => :unprocessable_entity }
  68
+      end
  69
+    end
  70
+  end
  71
+
  72
+  # DELETE /users/1
  73
+  # DELETE /users/1.xml
  74
+  def destroy
  75
+    @user = User.find(params[:id])
  76
+    @user.destroy
  77
+
  78
+    respond_to do |format|
  79
+      format.html { redirect_to(users_url) }
  80
+      format.xml  { head :ok }
  81
+    end
  82
+  end
  83
+end
5  episode-211/store/app/helpers/application_helper.rb
... ...
@@ -0,0 +1,5 @@
  1
+module ApplicationHelper
  2
+  def mark_required(object, attribute)
  3
+    "*" if object.class.validators_on(attribute).map(&:class).include? ActiveModel::Validations::PresenceValidator
  4
+  end
  5
+end
2  episode-211/store/app/helpers/users_helper.rb
... ...
@@ -0,0 +1,2 @@
  1
+module UsersHelper
  2
+end
3  episode-211/store/app/models/user.rb
... ...
@@ -0,0 +1,3 @@
  1
+class User < ActiveRecord::Base
  2
+  validates :email, :presence => true, :uniqueness => true, :email_format => true
  3
+end
14  episode-211/store/app/views/layouts/application.html.erb
... ...
@@ -0,0 +1,14 @@
  1
+<!DOCTYPE html>
  2
+<html>
  3
+<head>
  4
+  <title>Store</title>
  5
+  <%= stylesheet_link_tag :all %>
  6
+  <%= javascript_include_tag :defaults %>
  7
+  <%= csrf_meta_tag %>
  8
+</head>
  9
+<body>
  10
+
  11
+<%= yield %>
  12
+
  13
+</body>
  14
+</html>
10  episode-211/store/app/views/shared/_error_messages.html.erb
... ...
@@ -0,0 +1,10 @@
  1
+<% if target.errors.any? %>
  2
+<div id="errorExplanation">
  3
+  <h2><%= pluralize(target.errors.count, "error") %> prohibited this record from being saved:</h2>
  4
+  <ul>
  5
+  <% target.errors.full_messages.each do |msg| %>
  6
+    <li><%= msg %></li>
  7
+  <% end %>
  8
+  </ul>
  9
+</div>
  10
+<% end %>
15  episode-211/store/app/views/users/_form.html.erb
... ...
@@ -0,0 +1,15 @@
  1
+<%= form_for(@user) do |f| %>
  2
+  <%= render "shared/error_messages", :target => @user %>
  3
+  
  4
+  <div class="field">
  5
+    <%= f.label :name %><%= mark_required(@user, :name) %><br />
  6
+    <%= f.text_field :name %>
  7
+  </div>
  8
+  <div class="field">
  9
+    <%= f.label :email %><%= mark_required(@user, :email) %><br />
  10
+    <%= f.text_field :email %>
  11
+  </div>
  12
+  <div class="actions">
  13
+    <%= f.submit %>
  14
+  </div>
  15
+<% end %>
6  episode-211/store/app/views/users/edit.html.erb
... ...
@@ -0,0 +1,6 @@
  1
+<h1>Editing user</h1>
  2
+
  3
+<%= render 'form' %>
  4
+
  5
+<%= link_to 'Show', @user %> |
  6
+<%= link_to 'Back', users_path %>
25  episode-211/store/app/views/users/index.html.erb
... ...
@@ -0,0 +1,25 @@
  1
+<h1>Listing users</h1>
  2
+
  3
+<table>
  4
+  <tr>
  5
+    <th>Name</th>
  6
+    <th>Email</th>
  7
+    <th></th>
  8
+    <th></th>
  9
+    <th></th>
  10
+  </tr>
  11
+
  12
+<% @users.each do |user| %>
  13
+  <tr>
  14
+    <td><%= user.name %></td>
  15
+    <td><%= user.email %></td>
  16
+    <td><%= link_to 'Show', user %></td>
  17
+    <td><%= link_to 'Edit', edit_user_path(user) %></td>
  18
+    <td><%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %></td>
  19
+  </tr>
  20
+<% end %>
  21
+</table>
  22
+
  23
+<br />
  24
+
  25
+<%= link_to 'New User', new_user_path %>
5  episode-211/store/app/views/users/new.html.erb
... ...
@@ -0,0 +1,5 @@
  1
+<h1>New user</h1>
  2
+
  3
+<%= render 'form' %>
  4
+
  5
+<%= link_to 'Back', users_path %>
15  episode-211/store/app/views/users/show.html.erb
... ...
@@ -0,0 +1,15 @@
  1
+<p class="notice"><%= notice %></p>
  2
+
  3
+<p>
  4
+  <b>Name:</b>
  5
+  <%= @user.name %>
  6
+</p>
  7
+
  8
+<p>
  9
+  <b>Email:</b>
  10
+  <%= @user.email %>
  11
+</p>
  12
+
  13
+
  14
+<%= link_to 'Edit', edit_user_path(@user) %> |
  15
+<%= link_to 'Back', users_path %>
4  episode-211/store/config.ru
... ...
@@ -0,0 +1,4 @@
  1
+# This file is used by Rack-based servers to start the application.
  2
+
  3
+require ::File.expand_path('../config/environment',  __FILE__)
  4
+run Store::Application
46  episode-211/store/config/application.rb
... ...
@@ -0,0 +1,46 @@
  1
+require File.expand_path('../boot', __FILE__)
  2
+
  3
+require 'rails/all'
  4
+
  5
+# If you have a Gemfile, require the gems listed there, including any gems
  6
+# you've limited to :test, :development, or :production.
  7
+Bundler.require(:default, Rails.env) if defined?(Bundler)
  8
+
  9
+module Store
  10
+  class Application < Rails::Application
  11
+    # Settings in config/environments/* take precedence over those specified here.
  12
+    # Application configuration should go into files in config/initializers
  13
+    # -- all .rb files in that directory are automatically loaded.
  14
+
  15
+    # Add additional load paths for your own custom dirs
  16
+    # config.load_paths += %W( #{config.root}/extras )
  17
+
  18
+    # Only load the plugins named here, in the order given (default is alphabetical).
  19
+    # :all can be used as a placeholder for all plugins not explicitly named
  20
+    # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
  21
+
  22
+    # Activate observers that should always be running
  23
+    # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
  24
+
  25
+    # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
  26
+    # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
  27
+    # config.time_zone = 'Central Time (US & Canada)'
  28
+
  29
+    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
  30
+    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
  31
+    # config.i18n.default_locale = :de
  32
+
  33
+    # Configure generators values. Many other options are available, be sure to check the documentation.
  34
+    # config.generators do |g|
  35
+    #   g.orm             :active_record
  36
+    #   g.template_engine :erb
  37
+    #   g.test_framework  :test_unit, :fixture => true
  38
+    # end
  39
+
  40
+    # Configure the default encoding used in templates for Ruby 1.9.
  41
+    config.encoding = "utf-8"
  42
+
  43
+    # Configure sensitive parameters which will be filtered from the log file.
  44
+    config.filter_parameters += [:password]
  45
+  end
  46
+end
6  episode-211/store/config/boot.rb
... ...
@@ -0,0 +1,6 @@
  1
+require 'rubygems'
  2
+# Set up gems listed in the Gemfile.
  3
+if File.exist?(File.expand_path('../../Gemfile', __FILE__))
  4
+  require 'bundler'
  5
+  Bundler.setup
  6
+end
22  episode-211/store/config/database.yml
... ...
@@ -0,0 +1,22 @@
  1
+# SQLite version 3.x
  2
+#   gem install sqlite3-ruby (not necessary on OS X Leopard)
  3
+development:
  4
+  adapter: sqlite3
  5
+  database: db/development.sqlite3
  6
+  pool: 5
  7
+  timeout: 5000
  8
+
  9
+# Warning: The database defined as "test" will be erased and
  10
+# re-generated from your development database when you run "rake".
  11
+# Do not set this db to the same as development or production.
  12
+test:
  13
+  adapter: sqlite3
  14
+  database: db/test.sqlite3
  15
+  pool: 5
  16
+  timeout: 5000
  17
+
  18
+production:
  19
+  adapter: sqlite3
  20
+  database: db/production.sqlite3
  21
+  pool: 5
  22
+  timeout: 5000
5  episode-211/store/config/environment.rb
... ...
@@ -0,0 +1,5 @@
  1
+# Load the rails application
  2
+require File.expand_path('../application', __FILE__)
  3
+
  4
+# Initialize the rails application
  5
+Store::Application.initialize!
19  episode-211/store/config/environments/development.rb
... ...
@@ -0,0 +1,19 @@
  1
+Store::Application.configure do
  2
+  # Settings specified here will take precedence over those in config/environment.rb
  3
+
  4
+  # In the development environment your application's code is reloaded on
  5
+  # every request.  This slows down response time but is perfect for development
  6
+  # since you don't have to restart the webserver when you make code changes.
  7
+  config.cache_classes = false
  8
+
  9
+  # Log error messages when you accidentally call methods on nil.
  10
+  config.whiny_nils = true
  11
+
  12
+  # Show full error reports and disable caching
  13
+  config.consider_all_requests_local       = true
  14
+  config.action_view.debug_rjs             = true
  15
+  config.action_controller.perform_caching = false
  16
+
  17
+  # Don't care if the mailer can't send
  18
+  config.action_mailer.raise_delivery_errors = false
  19
+end
42  episode-211/store/config/environments/production.rb
... ...
@@ -0,0 +1,42 @@
  1
+Store::Application.configure do
  2
+  # Settings specified here will take precedence over those in config/environment.rb
  3
+
  4
+  # The production environment is meant for finished, "live" apps.
  5
+  # Code is not reloaded between requests
  6
+  config.cache_classes = true
  7
+
  8
+  # Full error reports are disabled and caching is turned on
  9
+  config.consider_all_requests_local       = false
  10
+  config.action_controller.perform_caching = true
  11
+
  12
+  # Specifies the header that your server uses for sending files
  13
+  config.action_dispatch.x_sendfile_header = "X-Sendfile"
  14
+
  15
+  # For nginx:
  16
+  # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
  17
+
  18
+  # If you have no front-end server that supports something like X-Sendfile,
  19
+  # just comment this out and Rails will serve the files
  20
+
  21
+  # See everything in the log (default is :info)
  22
+  # config.log_level = :debug
  23
+
  24
+  # Use a different logger for distributed setups
  25
+  # config.logger = SyslogLogger.new
  26
+
  27
+  # Use a different cache store in production
  28
+  # config.cache_store = :mem_cache_store
  29
+
  30
+  # Disable Rails's static asset server
  31
+  # In production, Apache or nginx will already do this
  32
+  config.serve_static_assets = false
  33
+
  34
+  # Enable serving of images, stylesheets, and javascripts from an asset server
  35
+  # config.action_controller.asset_host = "http://assets.example.com"
  36
+
  37
+  # Disable delivery errors, bad email addresses will be ignored
  38
+  # config.action_mailer.raise_delivery_errors = false
  39
+
  40
+  # Enable threaded mode
  41
+  # config.threadsafe!
  42
+end
32  episode-211/store/config/environments/test.rb
... ...
@@ -0,0 +1,32 @@
  1
+Store::Application.configure do
  2
+  # Settings specified here will take precedence over those in config/environment.rb
  3
+
  4
+  # The test environment is used exclusively to run your application's
  5
+  # test suite.  You never need to work with it otherwise.  Remember that
  6
+  # your test database is "scratch space" for the test suite and is wiped
  7
+  # and recreated between test runs.  Don't rely on the data there!
  8
+  config.cache_classes = true
  9
+
  10
+  # Log error messages when you accidentally call methods on nil.
  11
+  config.whiny_nils = true
  12
+
  13
+  # Show full error reports and disable caching
  14
+  config.consider_all_requests_local       = true
  15
+  config.action_controller.perform_caching = false
  16
+
  17
+  # Raise exceptions instead of rendering exception templates
  18
+  config.action_dispatch.show_exceptions = false
  19
+
  20
+  # Disable request forgery protection in test environment
  21
+  config.action_controller.allow_forgery_protection    = false
  22
+
  23
+  # Tell Action Mailer not to deliver emails to the real world.
  24
+  # The :test delivery method accumulates sent emails in the
  25
+  # ActionMailer::Base.deliveries array.
  26
+  config.action_mailer.delivery_method = :test
  27
+
  28
+  # Use SQL instead of Active Record's schema dumper when creating the test database.
  29
+  # This is necessary if your schema can't be completely dumped by the schema dumper,
  30
+  # like if you have constraints or database-specific column types
  31
+  # config.active_record.schema_format = :sql
  32
+end
7  episode-211/store/config/initializers/backtrace_silencers.rb
... ...
@@ -0,0 +1,7 @@
  1
+# Be sure to restart your server when you modify this file.
  2
+
  3
+# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
  4
+# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
  5
+
  6
+# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
  7
+# Rails.backtrace_cleaner.remove_silencers!
10  episode-211/store/config/initializers/inflections.rb
... ...
@@ -0,0 +1,10 @@
  1
+# Be sure to restart your server when you modify this file.
  2
+
  3
+# Add new inflection rules using the following format 
  4
+# (all these examples are active by default):
  5
+# ActiveSupport::Inflector.inflections do |inflect|
  6
+#   inflect.plural /^(ox)$/i, '\1en'
  7
+#   inflect.singular /^(ox)en/i, '\1'
  8
+#   inflect.irregular 'person', 'people'
  9
+#   inflect.uncountable %w( fish sheep )
  10
+# end
5  episode-211/store/config/initializers/mime_types.rb
... ...
@@ -0,0 +1,5 @@
  1
+# Be sure to restart your server when you modify this file.
  2
+
  3
+# Add new mime types for use in respond_to blocks:
  4
+# Mime::Type.register "text/richtext", :rtf
  5
+# Mime::Type.register_alias "text/html", :iphone
7  episode-211/store/config/initializers/secret_token.rb
... ...
@@ -0,0 +1,7 @@
  1
+# Be sure to restart your server when you modify this file.
  2
+
  3
+# Your secret key for verifying the integrity of signed cookies.
  4
+# If you change this key, all old signed cookies will become invalid!
  5
+# Make sure the secret is at least 30 characters and all random, 
  6
+# no regular words or you'll be exposed to dictionary attacks.
  7
+Rails.application.config.secret_token = '23fa89211c74af69498ab3a016492393b55344b46ce287e05f8f39606becd2d6d364606f07516ae5471b6682588186688aeff33b1090f42d39d64c8794f4253e'
8  episode-211/store/config/initializers/session_store.rb
... ...
@@ -0,0 +1,8 @@
  1
+# Be sure to restart your server when you modify this file.
  2
+
  3
+Rails.application.config.session_store :cookie_store, :key => '_store_session'
  4
+
  5
+# Use the database for sessions instead of the cookie-based default,
  6
+# which shouldn't be used to store highly confidential information
  7
+# (create the session table with "rake db:sessions:create")
  8
+# Rails.application.config.session_store :active_record_store
5  episode-211/store/config/locales/en.yml
... ...
@@ -0,0 +1,5 @@
  1
+# Sample localization file for English. Add more files in this directory for other locales.
  2
+# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
  3
+
  4
+en:
  5
+  hello: "Hello world"
61  episode-211/store/config/routes.rb
... ...
@@ -0,0 +1,61 @@
  1
+Store::Application.routes.draw do |map|
  2
+  resources :users
  3
+  root :to => "users#index"
  4
+
  5
+  # The priority is based upon order of creation:
  6
+  # first created -> highest priority.
  7
+
  8
+  # Sample of regular route:
  9
+  #   match 'products/:id' => 'catalog#view'
  10
+  # Keep in mind you can assign values other than :controller and :action
  11
+
  12
+  # Sample of named route:
  13
+  #   match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
  14
+  # This route can be invoked with purchase_url(:id => product.id)
  15
+
  16
+  # Sample resource route (maps HTTP verbs to controller actions automatically):
  17
+  #   resources :products
  18
+
  19
+  # Sample resource route with options:
  20
+  #   resources :products do
  21
+  #     member do
  22
+  #       get :short
  23
+  #       post :toggle
  24
+  #     end
  25
+  #
  26
+  #     collection do
  27
+  #       get :sold
  28
+  #     end
  29
+  #   end
  30
+
  31
+  # Sample resource route with sub-resources:
  32
+  #   resources :products do
  33
+  #     resources :comments, :sales
  34
+  #     resource :seller
  35
+  #   end
  36
+
  37
+  # Sample resource route with more complex sub-resources
  38
+  #   resources :products do
  39
+  #     resources :comments
  40
+  #     resources :sales do
  41
+  #       get :recent, :on => :collection
  42
+  #     end
  43
+  #   end
  44
+
  45
+  # Sample resource route within a namespace:
  46
+  #   namespace :admin do
  47
+  #     # Directs /admin/products/* to Admin::ProductsController
  48
+  #     # (app/controllers/admin/products_controller.rb)
  49
+  #     resources :products
  50
+  #   end
  51
+
  52
+  # You can have the root of your site routed with "root"
  53
+  # just remember to delete public/index.html.
  54
+  # root :to => "welcome#index"
  55
+
  56
+  # See how all your routes lay out with "rake routes"
  57
+
  58
+  # This is a legacy wild controller route that's not recommended for RESTful applications.
  59
+  # Note: This route will make all actions in every controller accessible via GET requests.
  60
+  # match ':controller(/:action(/:id(.:format)))'
  61
+end
14  episode-211/store/db/migrate/20100426050559_create_users.rb
... ...
@@ -0,0 +1,14 @@
  1
+class CreateUsers < ActiveRecord::Migration
  2
+  def self.up
  3
+    create_table :users do |t|
  4
+      t.string :name
  5
+      t.string :email
  6
+
  7
+      t.timestamps
  8
+    end
  9
+  end
  10
+
  11
+  def self.down
  12
+    drop_table :users
  13
+  end
  14
+end
21  episode-211/store/db/schema.rb
... ...
@@ -0,0 +1,21 @@
  1
+# This file is auto-generated from the current state of the database. Instead of editing this file, 
  2
+# please use the migrations feature of Active Record to incrementally modify your database, and
  3
+# then regenerate this schema definition.
  4
+#
  5
+# Note that this schema.rb definition is the authoritative source for your database schema. If you need
  6
+# to create the application database on another system, you should be using db:schema:load, not running
  7
+# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
  8
+# you'll amass, the slower it'll run and the greater likelihood for issues).
  9
+#
  10
+# It's strongly recommended to check this file into your version control system.
  11
+
  12
+ActiveRecord::Schema.define(:version => 20100426050559) do
  13
+
  14
+  create_table "users", :force => true do |t|
  15
+    t.string   "name"
  16
+    t.string   "email"
  17
+    t.datetime "created_at"
  18
+    t.datetime "updated_at"
  19
+  end
  20
+
  21
+end
7  episode-211/store/db/seeds.rb
... ...
@@ -0,0 +1,7 @@
  1
+# This file should contain all the record creation needed to seed the database with its default values.
  2
+# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
  3
+#
  4
+# Examples:
  5
+#
  6
+#   cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
  7
+#   Mayor.create(:name => 'Daley', :city => cities.first)
2  episode-211/store/doc/README_FOR_APP
... ...
@@ -0,0 +1,2 @@
  1
+Use this README file to introduce your application and point to useful places in the API for learning more.
  2
+Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
7  episode-211/store/lib/email_format_validator.rb
... ...
@@ -0,0 +1,7 @@
  1
+class EmailFormatValidator < ActiveModel::EachValidator
  2
+  def validate_each(object, attribute, value)
  3
+    unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
  4
+      object.errors[attribute] << (options[:message] || "is not formatted properly") 
  5
+    end
  6
+  end
  7
+end
26  episode-211/store/public/404.html
... ...
@@ -0,0 +1,26 @@
  1
+<!DOCTYPE html>
  2
+<html>
  3
+<head>
  4
+  <title>The page you were looking for doesn't exist (404)</title>
  5
+  <style type="text/css">
  6
+    body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
  7
+    div.dialog {
  8
+      width: 25em;
  9
+      padding: 0 4em;
  10
+      margin: 4em auto 0 auto;
  11
+      border: 1px solid #ccc;
  12
+      border-right-color: #999;
  13
+      border-bottom-color: #999;
  14
+    }
  15
+    h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
  16
+  </style>
  17
+</head>
  18
+
  19
+<body>
  20
+  <!-- This file lives in public/404.html -->
  21
+  <div class="dialog">
  22
+    <h1>The page you were looking for doesn't exist.</h1>
  23
+    <p>You may have mistyped the address or the page may have moved.</p>
  24
+  </div>
  25
+</body>
  26
+</html>
26  episode-211/store/public/422.html
... ...
@@ -0,0 +1,26 @@
  1
+<!DOCTYPE html>
  2
+<html>
  3
+<head>
  4
+  <title>The change you wanted was rejected (422)</title>
  5
+  <style type="text/css">
  6
+    body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
  7
+    div.dialog {
  8
+      width: 25em;
  9
+      padding: 0 4em;
  10
+      margin: 4em auto 0 auto;
  11
+      border: 1px solid #ccc;
  12
+      border-right-color: #999;
  13
+      border-bottom-color: #999;
  14
+    }
  15
+    h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
  16
+  </style>
  17
+</head>
  18
+
  19
+<body>
  20
+  <!-- This file lives in public/422.html -->
  21
+  <div class="dialog">
  22
+    <h1>The change you wanted was rejected.</h1>
  23
+    <p>Maybe you tried to change something you didn't have access to.</p>
  24
+  </div>
  25
+</body>
  26
+</html>
26  episode-211/store/public/500.html
... ...
@@ -0,0 +1,26 @@
  1
+<!DOCTYPE html>
  2
+<html>
  3
+<head>
  4
+  <title>We're sorry, but something went wrong (500)</title>
  5
+  <style type="text/css">
  6
+    body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
  7
+    div.dialog {
  8
+      width: 25em;
  9
+      padding: 0 4em;
  10
+      margin: 4em auto 0 auto;
  11
+      border: 1px solid #ccc;
  12
+      border-right-color: #999;
  13
+      border-bottom-color: #999;
  14
+    }
  15
+    h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
  16
+  </style>
  17
+</head>
  18
+
  19
+<body>
  20
+  <!-- This file lives in public/500.html -->
  21
+  <div class="dialog">
  22
+    <h1>We're sorry, but something went wrong.</h1>
  23
+    <p>We've been notified about this issue and we'll take a look at it shortly.</p>
  24
+  </div>
  25
+</body>
  26
+</html>
0  episode-211/store/public/favicon.ico
No changes.
2  episode-211/store/public/javascripts/application.js
... ...
@@ -0,0 +1,2 @@
  1
+// Place your application-specific JavaScript functions and classes here
  2
+// This file is automatically included by javascript_include_tag :defaults
965  episode-211/store/public/javascripts/controls.js
... ...
@@ -0,0 +1,965 @@
  1
+// script.aculo.us controls.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
  2
+
  3
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
  4
+//           (c) 2005-2009 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
  5
+//           (c) 2005-2009 Jon Tirsen (http://www.tirsen.com)
  6
+// Contributors:
  7
+//  Richard Livsey
  8
+//  Rahul Bhargava
  9
+//  Rob Wills
  10
+//
  11
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
  12
+// For details, see the script.aculo.us web site: http://script.aculo.us/
  13
+
  14
+// Autocompleter.Base handles all the autocompletion functionality
  15
+// that's independent of the data source for autocompletion. This
  16
+// includes drawing the autocompletion menu, observing keyboard
  17
+// and mouse events, and similar.
  18
+//
  19
+// Specific autocompleters need to provide, at the very least,
  20
+// a getUpdatedChoices function that will be invoked every time
  21
+// the text inside the monitored textbox changes. This method
  22
+// should get the text for which to provide autocompletion by
  23
+// invoking this.getToken(), NOT by directly accessing
  24
+// this.element.value. This is to allow incremental tokenized
  25
+// autocompletion. Specific auto-completion logic (AJAX, etc)
  26
+// belongs in getUpdatedChoices.
  27
+//
  28
+// Tokenized incremental autocompletion is enabled automatically
  29
+// when an autocompleter is instantiated with the 'tokens' option
  30
+// in the options parameter, e.g.:
  31
+// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
  32
+// will incrementally autocomplete with a comma as the token.
  33
+// Additionally, ',' in the above example can be replaced with
  34
+// a token array, e.g. { tokens: [',', '\n'] } which
  35
+// enables autocompletion on multiple tokens. This is most
  36
+// useful when one of the tokens is \n (a newline), as it
  37
+// allows smart autocompletion after linebreaks.
  38
+
  39
+if(typeof Effect == 'undefined')
  40
+  throw("controls.js requires including script.aculo.us' effects.js library");
  41
+
  42
+var Autocompleter = { };
  43
+Autocompleter.Base = Class.create({
  44
+  baseInitialize: function(element, update, options) {
  45
+    element          = $(element);
  46
+    this.element     = element;
  47
+    this.update      = $(update);
  48
+    this.hasFocus    = false;
  49
+    this.changed     = false;
  50
+    this.active      = false;
  51
+    this.index       = 0;
  52
+    this.entryCount  = 0;
  53
+    this.oldElementValue = this.element.value;
  54
+
  55
+    if(this.setOptions)
  56
+      this.setOptions(options);
  57
+    else
  58
+      this.options = options || { };
  59
+
  60
+    this.options.paramName    = this.options.paramName || this.element.name;
  61
+    this.options.tokens       = this.options.tokens || [];
  62
+    this.options.frequency    = this.options.frequency || 0.4;
  63
+    this.options.minChars     = this.options.minChars || 1;
  64
+    this.options.onShow       = this.options.onShow ||
  65
+      function(element, update){
  66
+        if(!update.style.position || update.style.position=='absolute') {
  67
+          update.style.position = 'absolute';
  68
+          Position.clone(element, update, {
  69
+            setHeight: false,
  70
+            offsetTop: element.offsetHeight
  71
+          });
  72
+        }
  73
+        Effect.Appear(update,{duration:0.15});
  74
+      };
  75
+    this.options.onHide = this.options.onHide ||
  76
+      function(element, update){ new Effect.Fade(update,{duration:0.15}) };
  77
+
  78
+    if(typeof(this.options.tokens) == 'string')
  79
+      this.options.tokens = new Array(this.options.tokens);
  80
+    // Force carriage returns as token delimiters anyway
  81
+    if (!this.options.tokens.include('\n'))
  82
+      this.options.tokens.push('\n');
  83
+
  84
+    this.observer = null;
  85
+
  86
+    this.element.setAttribute('autocomplete','off');
  87
+
  88
+    Element.hide(this.update);
  89
+
  90
+    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
  91
+    Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
  92
+  },
  93
+
  94
+  show: function() {
  95
+    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
  96
+    if(!this.iefix &&
  97
+      (Prototype.Browser.IE) &&
  98
+      (Element.getStyle(this.update, 'position')=='absolute')) {
  99
+      new Insertion.After(this.update,
  100
+       '<iframe id="' + this.update.id + '_iefix" '+