Permalink
Browse files

Initial import.

  • Loading branch information...
0 parents commit c65eeae5e2d9acc3948e1751e19b4a2e2cc5c6c5 Michael Bleigh committed Mar 11, 2010
Showing with 2,234 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +39 −0 Gemfile
  3. +154 −0 Gemfile.lock
  4. +243 −0 README
  5. +10 −0 Rakefile
  6. +3 −0 app/controllers/application_controller.rb
  7. +2 −0 app/controllers/notifications_controller.rb
  8. +21 −0 app/controllers/products_controller.rb
  9. +22 −0 app/controllers/users_controller.rb
  10. +2 −0 app/helpers/application_helper.rb
  11. +2 −0 app/helpers/notifications_helper.rb
  12. +2 −0 app/helpers/products_helper.rb
  13. +2 −0 app/helpers/users_helper.rb
  14. +24 −0 app/models/friend_set.rb
  15. +20 −0 app/models/notification.rb
  16. +21 −0 app/models/product.rb
  17. +20 −0 app/models/purchase.rb
  18. +30 −0 app/models/user.rb
  19. +43 −0 app/views/layouts/application.html.erb
  20. +16 −0 app/views/products/index.html.erb
  21. +19 −0 app/views/products/show.html.erb
  22. +14 −0 app/views/users/index.html.erb
  23. +38 −0 app/views/users/show.html.erb
  24. +4 −0 config.ru
  25. +42 −0 config/application.rb
  26. +17 −0 config/boot.rb
  27. +22 −0 config/database.yml
  28. +5 −0 config/environment.rb
  29. +19 −0 config/environments/development.rb
  30. +33 −0 config/environments/production.rb
  31. +29 −0 config/environments/test.rb
  32. +6 −0 config/initializers/amazon_ecs.rb
  33. +7 −0 config/initializers/backtrace_silencers.rb
  34. +7 −0 config/initializers/cookie_verification_secret.rb
  35. +95 −0 config/initializers/devise.rb
  36. +10 −0 config/initializers/inflections.rb
  37. +5 −0 config/initializers/mime_types.rb
  38. +2 −0 config/initializers/mongo.rb
  39. +2 −0 config/initializers/redis.rb
  40. +15 −0 config/initializers/session_store.rb
  41. +41 −0 config/locales/devise.en.yml
  42. +5 −0 config/locales/en.yml
  43. +69 −0 config/routes.rb
  44. +19 −0 db/migrate/20100311050013_devise_create_users.rb
  45. +14 −0 db/migrate/20100311060326_create_purchases.rb
  46. +34 −0 db/schema.rb
  47. +7 −0 db/seeds.rb
  48. +2 −0 doc/README_FOR_APP
  49. +58 −0 futurama_characters.txt
  50. 0 lib/tasks/.gitkeep
  51. +24 −0 lib/tasks/dbs.rake
  52. +94 −0 lib/tasks/populate.rake
  53. +26 −0 public/404.html
  54. +26 −0 public/422.html
  55. +26 −0 public/500.html
  56. 0 public/favicon.ico
  57. BIN public/images/rails.png
  58. +5 −0 public/robots.txt
  59. 0 public/stylesheets/.gitkeep
  60. +181 −0 public/stylesheets/master.css
  61. +10 −0 script/rails
  62. +450 −0 superhero_names.txt
  63. +9 −0 test/fixtures/purchases.yml
  64. +11 −0 test/fixtures/users.yml
  65. +8 −0 test/functional/notifications_controller_test.rb
  66. +8 −0 test/functional/products_controller_test.rb
  67. +8 −0 test/functional/users_controller_test.rb
  68. +4 −0 test/unit/helpers/notifications_helper_test.rb
  69. +4 −0 test/unit/helpers/products_helper_test.rb
  70. +4 −0 test/unit/helpers/users_helper_test.rb
  71. +8 −0 test/unit/purchase_test.rb
  72. +8 −0 test/unit/user_test.rb
  73. 0 tmp/restart.txt
  74. BIN vendor/cache/abstract-1.0.0.gem
  75. BIN vendor/cache/actionmailer-3.0.0.beta.gem
  76. BIN vendor/cache/actionpack-3.0.0.beta.gem
  77. BIN vendor/cache/activemodel-3.0.0.beta.gem
  78. BIN vendor/cache/activerecord-3.0.0.beta.gem
  79. BIN vendor/cache/activeresource-3.0.0.beta.gem
  80. BIN vendor/cache/activesupport-3.0.0.beta.gem
  81. BIN vendor/cache/amazon-ecs-0.5.7.gem
  82. BIN vendor/cache/arel-0.2.1.gem
  83. BIN vendor/cache/builder-2.1.2.gem
  84. BIN vendor/cache/bundler-0.9.11.gem
  85. BIN vendor/cache/devise-1.1.pre4.gem
  86. BIN vendor/cache/erubis-2.6.5.gem
  87. BIN vendor/cache/hpricot-0.8.2.gem
  88. BIN vendor/cache/i18n-0.3.5.gem
  89. BIN vendor/cache/imdb-0.6.4.gem
  90. BIN vendor/cache/jnunemaker-validatable-1.8.3.gem
  91. BIN vendor/cache/mail-2.1.3.gem
  92. BIN vendor/cache/memcache-client-1.7.8.gem
  93. BIN vendor/cache/mime-types-1.16.gem
  94. BIN vendor/cache/mongo-0.19.1.gem
  95. BIN vendor/cache/mongo_ext-0.19.1.gem
  96. BIN vendor/cache/mongo_mapper-0.7.1.gem
  97. BIN vendor/cache/ohm-0.0.33.gem
  98. BIN vendor/cache/rack-1.1.0.gem
  99. BIN vendor/cache/rack-mount-0.4.7.gem
  100. BIN vendor/cache/rack-test-0.5.3.gem
  101. BIN vendor/cache/rails-3.0.0.beta.gem
  102. BIN vendor/cache/rails3-generators-0.4.0.gem
  103. BIN vendor/cache/railties-3.0.0.beta.gem
  104. BIN vendor/cache/rake-0.8.7.gem
  105. BIN vendor/cache/ruby-hmac-0.4.0.gem
  106. BIN vendor/cache/sqlite3-ruby-1.2.5.gem
  107. BIN vendor/cache/text-format-1.0.0.gem
  108. BIN vendor/cache/text-hyphen-1.0.0.gem
  109. BIN vendor/cache/thor-0.13.4.gem
  110. BIN vendor/cache/tzinfo-0.3.17.gem
  111. BIN vendor/cache/warden-0.9.6.gem
  112. 0 vendor/plugins/.gitkeep
4 .gitignore
@@ -0,0 +1,4 @@
+.bundle
+db/*.sqlite3
+log/*.log
+tmp/**/*
39 Gemfile
@@ -0,0 +1,39 @@
+# Edit this Gemfile to bundle your application's dependencies.
+source 'http://gemcutter.org'
+
+
+gem "rails", "3.0.0.beta"
+
+gem 'rails3-generators'
+gem 'gloo', '>= 0.0.0.alpha.1', :git => 'git@github.com:intridea/gloo.git'
+
+gem 'haml'
+
+gem 'mongo_ext', '0.19.1', :require => 'mongo'
+gem 'mongo_mapper'
+gem 'warden'
+gem 'devise', '>= 1.1.pre4'
+gem 'redis'
+gem 'ohm'
+
+gem 'imdb', :require => nil
+gem 'amazon-ecs', :require => 'amazon/ecs'
+
+## Bundle edge rails:
+# gem "rails", :git => "git://github.com/rails/rails.git"
+
+# ActiveRecord requires a database adapter. By default,
+# Rails has selected sqlite3.
+gem "sqlite3-ruby", :require => "sqlite3"
+
+## Bundle the gems you use:
+# gem "bj"
+# gem "hpricot", "0.6"
+# gem "sqlite3-ruby", :require => "sqlite3"
+# gem "aws-s3", :require => "aws/s3"
+
+## Bundle gems used only in certain environments:
+# gem "rspec", :group => :test
+# group :test do
+# gem "webrat"
+# end
154 Gemfile.lock
@@ -0,0 +1,154 @@
+---
+dependencies:
+ rails:
+ group:
+ - :default
+ version: = 3.0.0.beta
+ mongo_mapper:
+ group:
+ - :default
+ version: ">= 0"
+ amazon-ecs:
+ group:
+ - :default
+ version: ">= 0"
+ require:
+ - amazon/ecs
+ sqlite3-ruby:
+ group:
+ - :default
+ version: ">= 0"
+ require:
+ - sqlite3
+ mongo_ext:
+ group:
+ - :default
+ version: = 0.19.1
+ require:
+ - mongo
+ haml:
+ group:
+ - :default
+ version: ">= 0"
+ imdb:
+ group:
+ - :default
+ version: ">= 0"
+ require: []
+
+ rails3-generators:
+ group:
+ - :default
+ version: ">= 0"
+ devise:
+ group:
+ - :default
+ version: ">= 1.1.pre4"
+ redis:
+ group:
+ - :default
+ version: ">= 0"
+ warden:
+ group:
+ - :default
+ version: ">= 0"
+ gloo:
+ group:
+ - :default
+ version: ">= 0.0.0.alpha.1"
+ ohm:
+ group:
+ - :default
+ version: ">= 0"
+specs:
+- rake:
+ version: 0.8.7
+- activeresource:
+ version: 3.0.0.beta
+- mongo:
+ version: 0.19.1
+- tzinfo:
+ version: 0.3.17
+- text-format:
+ version: 1.0.0
+- amazon-ecs:
+ version: 0.5.7
+- rails:
+ version: 3.0.0.beta
+- activerecord:
+ version: 3.0.0.beta
+- mongo_mapper:
+ version: 0.7.1
+- memcache-client:
+ version: 1.7.8
+- haml:
+ version: 2.2.20
+- mongo_ext:
+ version: 0.19.1
+- sqlite3-ruby:
+ version: 1.2.5
+- railties:
+ version: 3.0.0.beta
+- thor:
+ version: 0.13.4
+- imdb:
+ version: 0.6.4
+- jnunemaker-validatable:
+ version: 1.8.3
+- ruby-hmac:
+ version: 0.4.0
+- abstract:
+ version: 1.0.0
+- mime-types:
+ version: "1.16"
+- mail:
+ version: 2.1.3
+- rack:
+ version: 1.1.0
+- activemodel:
+ version: 3.0.0.beta
+- rails3-generators:
+ version: 0.4.0
+- rack-mount:
+ version: 0.4.7
+- arel:
+ version: 0.2.1
+- erubis:
+ version: 2.6.5
+- devise:
+ version: 1.1.pre4
+- bundler:
+ version: 0.9.11
+- actionpack:
+ version: 3.0.0.beta
+- actionmailer:
+ version: 3.0.0.beta
+- rack-test:
+ version: 0.5.3
+- i18n:
+ version: 0.3.5
+- builder:
+ version: 2.1.2
+- redis:
+ version: 0.1.2
+- ohm:
+ version: 0.0.33
+- warden:
+ version: 0.9.6
+- activesupport:
+ version: 3.0.0.beta
+- gloo:
+ version: 0.0.0.alpha.1
+ source: 0
+- hpricot:
+ version: 0.8.2
+- text-hyphen:
+ version: 1.0.0
+hash: 550f97e7b85a1834197bf52e1fcd36153f1dafbd
+sources:
+- Git:
+ uri: git@github.com:intridea/gloo.git
+ git: git@github.com:intridea/gloo.git
+ ref: dde293f2e7f44fbadce417b3333a6682cbdc7baa
+- Rubygems:
+ uri: http://gemcutter.org
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.expand_path('../config/application', __FILE__)
+
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+Rails::Application.load_tasks
3 app/controllers/application_controller.rb
@@ -0,0 +1,3 @@
+class ApplicationController < ActionController::Base
+ protect_from_forgery
+end
2 app/controllers/notifications_controller.rb
@@ -0,0 +1,2 @@
+class NotificationsController < ApplicationController
+end
21 app/controllers/products_controller.rb
@@ -0,0 +1,21 @@
+class ProductsController < ApplicationController
+ def index
+ conditions = {}
+ conditions.merge!('info.cast' => params[:actor]) if params[:actor]
+ @products = Product.all(:conditions => conditions, :sort => ['title', 1], :limit => 50)
+ end
+
+ def purchase
+ @product = Product.find_by_id(params[:id])
+ if Purchase.create(:user => current_user, :product => @product)
+ flash[:notice] = "You have purchased '#{@product.title}'"
+ else
+ flash[:error] = "Problem purchasing '#{@product.title}'"
+ end
+ redirect_to :back
+ end
+
+ def show
+ @product = Product.find_by_id(params[:id])
+ end
+end
22 app/controllers/users_controller.rb
@@ -0,0 +1,22 @@
+class UsersController < ApplicationController
+ def index
+ @users = User.all(:order => :name)
+ end
+
+ def follow
+ @user = User.find_by_id(params[:id])
+ if @user && current_user.follow!(@user)
+ flash[:notice] = "You are now following #{@user.name}."
+ else
+ flash[:error] = "Unable to follow #{@user.name}."
+ end
+ redirect_to :back
+ end
+
+ def show
+ @user = User.find_by_id(params[:id])
+ @followers = @user.followers
+ @followings = @user.followings
+ @friends = @user.friends
+ end
+end
2 app/helpers/application_helper.rb
@@ -0,0 +1,2 @@
+module ApplicationHelper
+end
2 app/helpers/notifications_helper.rb
@@ -0,0 +1,2 @@
+module NotificationsHelper
+end
2 app/helpers/products_helper.rb
@@ -0,0 +1,2 @@
+module ProductsHelper
+end
2 app/helpers/users_helper.rb
@@ -0,0 +1,2 @@
+module UsersHelper
+end
24 app/models/friend_set.rb
@@ -0,0 +1,24 @@
+class FriendSet
+ def self.following_ids_for(user)
+ Red.smembers("user:#{user.id}:followings")
+ end
+
+ def self.follower_ids_for(user)
+ Red.smembers("user:#{user.id}:followers")
+ end
+
+ def self.follow!(user, followed_user)
+ return false if user == followed_user
+ Red.sadd("user:#{user.id}:followings", followed_user.id)
+ Red.sadd("user:#{followed_user.id}:followers", user.id)
+ true
+ end
+
+ def self.following?(user, other_user)
+ Red.sismember("user:#{user.id}:followings", other_user.id)
+ end
+
+ def self.friend_ids_for(user)
+ Red.sinter("user:#{user.id}:followings", "user:#{user.id}:followers")
+ end
+end
20 app/models/notification.rb
@@ -0,0 +1,20 @@
+class Notification
+ def self.deliver!(message, opts = {})
+ opts[:to].each do |follower_id|
+ Red.lpush "user:#{follower_id}:notifications", {:message => message, :timestamp => Time.now}.to_json
+ end
+ end
+
+ def self.for_user(user, limit = -1)
+ Red.lrange("user:#{user.id}:notifications", 0, limit).map{|n| Notification.new(ActiveSupport::JSON.decode(n))}
+ end
+
+ def initialize(attributes = {})
+ @attributes = attributes
+ end
+
+ def method_missing(name, *args)
+ super unless @attributes && @attributes.key?(name.to_s)
+ @attributes[name.to_s]
+ end
+end
21 app/models/product.rb
@@ -0,0 +1,21 @@
+require 'gloo/active_record'
+
+class Product
+ include MongoMapper::Document
+
+ key :type, String
+ key :image, String
+ key :title, String
+
+ key :info, Hash
+
+ def purchases
+ Purchase.where(:product_id => self.id.to_s)
+ end
+
+ def users
+ User.join(:purchases).where('purchases.product_id' => self.id.to_s)
+ end
+
+ timestamps!
+end
20 app/models/purchase.rb
@@ -0,0 +1,20 @@
+class Purchase < ActiveRecord::Base
+ belongs_to :user
+
+ validates_uniqueness_of :product_id, :scope => :user_id
+
+ def product=(product)
+ self.product_id = product.id.to_s
+ @product = product
+ end
+
+ def product
+ @product ||= Product.find_by_id(product_id)
+ end
+
+ after_create :notify_followers
+
+ def notify_followers
+ Notification.deliver! "<b><a href='/users/#{user.id}'>#{user.name}</a></b> purchased <b><a href='/products/#{product.id}'>#{product.title}</a></b>", :to => (user.follower_ids + [user.id])
+ end
+end
30 app/models/user.rb
@@ -0,0 +1,30 @@
+class User < ActiveRecord::Base
+ # Include default devise modules. Others available are:
+ # :http_authenticatable, :token_authenticatable, :lockable, :timeoutable and :activatable
+ devise :registerable, :rememberable, :authenticatable
+
+ def following_ids; FriendSet.following_ids_for(self) end
+ def followings; User.where(:id => following_ids) end
+ def following?(user); FriendSet.following?(self, user) end
+ def follow!(user); FriendSet.follow!(self, user) end
+
+ def friend_ids; FriendSet.friend_ids_for(self) end
+ def friends; User.where(:id => friend_ids) end
+
+ def follower_ids; FriendSet.follower_ids_for(self) end
+ def followers; User.where(:id => follower_ids) end
+
+ has_many :purchases do
+ def products
+ ids = all.collect{|p| Mongo::ObjectID.from_string(p.product_id)}
+ Product.find(*ids)
+ end
+ end
+
+ def products
+ purchases.products
+ end
+
+ # Setup accessible (or protected) attributes for your model
+ attr_accessible :email, :password, :password_confirmation
+end
43 app/views/layouts/application.html.erb
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Schema4Less - Social Shopping!</title>
+ <%= stylesheet_link_tag 'master' %>
+ </head>
+ <body>
+ <header id="top">
+ <aside id='user-bar'>
+ <% if user_signed_in? %>
+ Welcome, <b><%= current_user.name %></b>. <%= link_to "Sign Out", '/users/sign_out' %>
+ <% else %>
+ <%= link_to 'Sign In', '/users/sign_in' %> |
+ <%= link_to 'Sign Up', '/users/sign_up' %>
+ <% end %>
+ </aside>
+ <h1>Schema4Less</h1>
+ <nav id='menu'>
+ <ul>
+ <li><%= link_to 'Products', '/products' %></li>
+ <li><%= link_to 'People', '/users' %></li>
+ <% if user_signed_in? %>
+ <li><%= link_to 'Notifications', user_path(current_user) %></li>
+ <% end %>
+ </ul>
+ </nav>
+ </header>
+ <% if flash.keys.any? %>
+ <section class='flash'>
+ <ul><% flash.each_pair do |k,v| %>
+ <li><b><%= k.to_s.titleize %>:</b> <%= v%>.</li>
+ <% end %></ul>
+ </section>
+ <% end %>
+ <section id="body">
+ <%= yield %>
+ </section>
+ <footer>
+ Copyright &copy; 2010 Intridea, Inc. No rights reserved.
+ </footer>
+ </body>
+</html>
16 app/views/products/index.html.erb
@@ -0,0 +1,16 @@
+<h1>Products<% if params[:actor]%> with <%= params[:actor] %><% end %></h1>
+<table>
+ <tbody>
+ <% @products.each do |product| %>
+ <tr>
+ <th><%= link_to image_tag(product.image), product %></th>
+ <td><%= link_to truncate(raw(product.title), 60), product %></td>
+ <% if user_signed_in? && !current_user.purchases.find_by_product_id(product.id.to_s) %>
+ <td><%= button_to 'Purchase', purchase_product_path(product) %></td>
+ <% else %>
+ <td/>
+ <% end %>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
19 app/views/products/show.html.erb
@@ -0,0 +1,19 @@
+<h1><%= @product.title %></h1>
+<table>
+ <tbody>
+ <tr>
+ <th><%= image_tag(@product.image) %></th>
+ <td>
+ <dl>
+ <% @product.info.each_pair do |k, v| %>
+ <% if k == 'cast'%>
+ <dt>Cast:</dt><dd><%=raw v.map{|actor| link_to(actor, products_path(:actor => actor))}.to_sentence %></dd>
+ <% else %>
+ <dt><%= k.titleize %>:</dt><dd><%= v %>&nbsp;</dd>
+ <% end %>
+ <% end %>
+ </dl>
+ </td>
+ </tr>
+ </tbody>
+</table>
14 app/views/users/index.html.erb
@@ -0,0 +1,14 @@
+<table>
+ <tbody>
+ <% @users.each do |user| %>
+ <tr>
+ <td><%= link_to user.name, user %></td>
+ <% if user_signed_in? && user != current_user && !current_user.following?(user) %>
+ <td><%= button_to 'Follow', follow_user_path(user) %></td>
+ <% else %>
+ <td/>
+ <% end %>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
38 app/views/users/show.html.erb
@@ -0,0 +1,38 @@
+<aside class='sidebar social_graph'>
+ <h1>Followings <em>(<%= @followings.size %>)</em></h1>
+
+ <ul><% @followings.each do |u| %>
+ <li><%= link_to u.name, u %></li>
+ <% end %></ul>
+
+ <h1>Followers <em>(<%= @followers.size%>)</em></h1>
+
+ <ul><% @followers.each do |u| %>
+ <li><%= link_to u.name, u %></li>
+ <% end %></ul>
+
+ <h1>Friends <em>(<%= @friends.size %>)</em></h1>
+
+ <ul><% @friends.each do |u| %>
+ <li><%= link_to u.name, u %></li>
+ <% end %></ul>
+</aside>
+
+<section id='main'>
+ <h1><%= @user.name %>'s Profile</h1>
+
+ <h2>Purchases</h2>
+ <% for product in @user.products %>
+ <%=link_to image_tag(product.image, :title => product.title), product %>
+ <% end %>
+
+ <h2>News Feed</h2>
+ <ul class='notifications'>
+ <% for notification in Notification.for_user(@user, 20) %>
+ <li>
+ <time><%= time_ago_in_words(Time.parse(notification.timestamp)) %> ago</time>
+ <span class='message'><%=raw notification.message %></span>
+ </li>
+ <% end %>
+ </ul>
+</section>
4 config.ru
@@ -0,0 +1,4 @@
+# This file is used by Rack-based servers to start the application.
+
+require ::File.expand_path('../config/environment', __FILE__)
+run Schema4less::Application
42 config/application.rb
@@ -0,0 +1,42 @@
+require File.expand_path('../boot', __FILE__)
+
+require 'rails/all'
+
+# Auto-require default libraries and those for the current Rails environment.
+Bundler.require :default, Rails.env
+
+module Schema4less
+ class Application < Rails::Application
+ # 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( #{config.root}/extras )
+
+ # 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 ]
+
+ # 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. Default is UTC.
+ # config.time_zone = 'Central Time (US & Canada)'
+
+ # 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
+
+ # Configure generators values. Many other options are available, be sure to check the documentation.
+ # config.generators do |g|
+ # g.orm :active_record
+ # g.template_engine :erb
+ # g.test_framework :test_unit, :fixture => true
+ # end
+
+ # Configure sensitive parameters which will be filtered from the log file.
+ config.filter_parameters << :password
+ end
+end
17 config/boot.rb
@@ -0,0 +1,17 @@
+# Use Bundler (preferred)
+begin
+ require File.expand_path('../../.bundle/environment', __FILE__)
+rescue LoadError
+ require 'rubygems'
+ require 'bundler'
+ Bundler.setup
+
+ # To use 2.x style vendor/rails and RubyGems
+ #
+ # vendor_rails = File.expand_path('../../vendor/rails', __FILE__)
+ # if File.exist?(vendor_rails)
+ # Dir["#{vendor_rails}/*/lib"].each { |path| $:.unshift(path) }
+ # end
+ #
+ # require 'rubygems'
+end
22 config/database.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
5 config/environment.rb
@@ -0,0 +1,5 @@
+# Load the rails application
+require File.expand_path('../application', __FILE__)
+
+# Initialize the rails application
+Schema4less::Application.initialize!
19 config/environments/development.rb
@@ -0,0 +1,19 @@
+Schema4less::Application.configure do
+ # Settings specified here will take precedence over those in config/environment.rb
+
+ # In the development environment your application's code is reloaded on
+ # every request. This slows down response time but is perfect for development
+ # since you don't have to restart the webserver when you make code changes.
+ config.cache_classes = false
+
+ # Log error messages when you accidentally call methods on nil.
+ config.whiny_nils = true
+
+ # Show full error reports and disable caching
+ config.consider_all_requests_local = true
+ config.action_view.debug_rjs = true
+ config.action_controller.perform_caching = false
+
+ # Don't care if the mailer can't send
+ config.action_mailer.raise_delivery_errors = false
+end
33 config/environments/production.rb
@@ -0,0 +1,33 @@
+Schema4less::Application.configure do
+ # Settings specified here will take precedence over those in config/environment.rb
+
+ # The production environment is meant for finished, "live" apps.
+ # Code is not reloaded between requests
+ config.cache_classes = true
+
+ # Full error reports are disabled and caching is turned on
+ config.consider_all_requests_local = false
+ config.action_controller.perform_caching = true
+
+ # See everything in the log (default is :info)
+ # config.log_level = :debug
+
+ # Use a different logger for distributed setups
+ # config.logger = SyslogLogger.new
+
+ # Use a different cache store in production
+ # config.cache_store = :mem_cache_store
+
+ # Disable Rails's static asset server
+ # In production, Apache or nginx will already do this
+ config.serve_static_assets = false
+
+ # Enable serving of images, stylesheets, and javascripts from an asset server
+ # config.action_controller.asset_host = "http://assets.example.com"
+
+ # Disable delivery errors, bad email addresses will be ignored
+ # config.action_mailer.raise_delivery_errors = false
+
+ # Enable threaded mode
+ # config.threadsafe!
+end
29 config/environments/test.rb
@@ -0,0 +1,29 @@
+Schema4less::Application.configure do
+ # Settings specified here will take precedence over those in config/environment.rb
+
+ # The test environment is used exclusively to run your application's
+ # test suite. You never need to work with it otherwise. Remember that
+ # your test database is "scratch space" for the test suite and is wiped
+ # and recreated between test runs. Don't rely on the data there!
+ config.cache_classes = true
+
+ # Log error messages when you accidentally call methods on nil.
+ config.whiny_nils = true
+
+ # Show full error reports and disable caching
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+
+ # Disable request forgery protection in test environment
+ config.action_controller.allow_forgery_protection = false
+
+ # Tell Action Mailer not to deliver emails to the real world.
+ # The :test delivery method accumulates sent emails in the
+ # ActionMailer::Base.deliveries array.
+ config.action_mailer.delivery_method = :test
+
+ # Use SQL instead of Active Record's schema dumper when creating the test database.
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
+ # like if you have constraints or database-specific column types
+ # config.active_record.schema_format = :sql
+end
6 config/initializers/amazon_ecs.rb
@@ -0,0 +1,6 @@
+require 'amazon/ecs'
+
+Amazon::Ecs.options = {
+ :aWS_access_key_id => '1250X0FQJ6Y3DV5QCFR2',
+ :aWS_secret_key => 'pIzhXqqrYOTegS9qr4ml7M+xBfty4WcnYwgHVt7J'
+}
7 config/initializers/backtrace_silencers.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
+# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+
+# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
+# Rails.backtrace_cleaner.remove_silencers!
7 config/initializers/cookie_verification_secret.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key for verifying the integrity of signed cookies.
+# If you change this key, all old signed cookies will become invalid!
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+ActionController::Base.cookie_verifier_secret = '131c21d6d6b4cc6f5602942fa471c71c5ca125bbd9f072e6900ebb682be8d61ebf65565180f4997506ac31f044ea5299cea0e5532fad2d19f43b80a94ed302a7'
95 config/initializers/devise.rb
@@ -0,0 +1,95 @@
+# Use this hook to configure devise mailer, warden hooks and so forth. The first
+# four configuration values can also be set straight in your models.
+Devise.setup do |config|
+ # Configure the e-mail address which will be shown in DeviseMailer.
+ config.mailer_sender = "please-change-me@config-initializers-devise.com"
+
+ # ==> Configuration for :authenticatable
+ # Invoke `rake secret` and use the printed value to setup a pepper to generate
+ # the encrypted password. By default no pepper is used.
+ # config.pepper = "rake secret output"
+
+ # Configure how many times you want the password is reencrypted. Default is 10.
+ # config.stretches = 10
+
+ # Define which will be the encryption algorithm. Supported algorithms are :sha1
+ # (default), :sha512 and :bcrypt. Devise also supports encryptors from others
+ # authentication tools as :clearance_sha1, :authlogic_sha512 (then you should set
+ # stretches above to 20 for default behavior) and :restful_authentication_sha1
+ # (then you should set stretches to 10, and copy REST_AUTH_SITE_KEY to pepper)
+ # config.encryptor = :sha1
+
+ # Configure which keys are used when authenticating an user. By default is
+ # just :email. You can configure it to use [:username, :subdomain], so for
+ # authenticating an user, both parameters are required. Remember that those
+ # parameters are used only when authenticating and not when retrieving from
+ # session. If you need permissions, you should implement that in a before filter.
+ # config.authentication_keys = [ :email ]
+
+ # The realm used in Http Basic Authentication
+ # config.http_authentication_realm = "Application"
+
+ # ==> Configuration for :confirmable
+ # The time you want give to your user to confirm his account. During this time
+ # he will be able to access your application without confirming. Default is nil.
+ # config.confirm_within = 2.days
+
+ # ==> Configuration for :rememberable
+ # The time the user will be remembered without asking for credentials again.
+ # config.remember_for = 2.weeks
+
+ # ==> Configuration for :timeoutable
+ # The time you want to timeout the user session without activity. After this
+ # time the user will be asked for credentials again.
+ # config.timeout_in = 10.minutes
+
+ # ==> Configuration for :lockable
+ # Number of authentication tries before locking an account.
+ # config.maximum_attempts = 20
+
+ # Defines which strategy will be used to unlock an account.
+ # :email = Sends an unlock link to the user email
+ # :time = Reanables login after a certain ammount of time (see :unlock_in below)
+ # :both = enables both strategies
+ # config.unlock_strategy = :both
+
+ # Time interval to unlock the account if :time is enabled as unlock_strategy.
+ # config.unlock_in = 1.hour
+
+ # ==> Configuration for :token_authenticatable
+ # Defines name of the authentication token params key
+ # config.token_authentication_key = :auth_token
+
+ # ==> General configuration
+ # Load and configure the ORM. Supports :active_record (default), :mongo_mapper
+ # (requires mongo_ext installed) and :data_mapper (experimental).
+ require 'devise/orm/active_record'
+
+ # Turn scoped views on. Before rendering "sessions/new", it will first check for
+ # "sessions/users/new". It's turned off by default because it's slower if you
+ # are using only default views.
+ # config.scoped_views = true
+
+ # By default, devise detects the role accessed based on the url. So whenever
+ # accessing "/users/sign_in", it knows you are accessing an User. This makes
+ # routes as "/sign_in" not possible, unless you tell Devise to use the default
+ # scope, setting true below.
+ config.use_default_scope = true
+
+ # Configure the default scope used by Devise. By default it's the first devise
+ # role declared in your routes.
+ config.default_scope = :user
+
+ # If you want to use other strategies, that are not (yet) supported by Devise,
+ # you can configure them inside the config.warden block. The example below
+ # allows you to setup OAuth, using http://github.com/roman/warden_oauth
+ #
+ # config.warden do |manager|
+ # manager.oauth(:twitter) do |twitter|
+ # twitter.consumer_secret = <YOUR CONSUMER SECRET>
+ # twitter.consumer_key = <YOUR CONSUMER KEY>
+ # twitter.options :site => 'http://twitter.com'
+ # end
+ # manager.default_strategies.unshift :twitter_oauth
+ # end
+end
10 config/initializers/inflections.rb
@@ -0,0 +1,10 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new inflection rules using the following format
+# (all these examples are active by default):
+# ActiveSupport::Inflector.inflections do |inflect|
+# inflect.plural /^(ox)$/i, '\1en'
+# inflect.singular /^(ox)en/i, '\1'
+# inflect.irregular 'person', 'people'
+# inflect.uncountable %w( fish sheep )
+# end
5 config/initializers/mime_types.rb
@@ -0,0 +1,5 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new mime types for use in respond_to blocks:
+# Mime::Type.register "text/richtext", :rtf
+# Mime::Type.register_alias "text/html", :iphone
2 config/initializers/mongo.rb
@@ -0,0 +1,2 @@
+MongoMapper.connection = Mongo::Connection.new
+MongoMapper.database = 'schema4less'
2 config/initializers/redis.rb
@@ -0,0 +1,2 @@
+Ohm.connect
+Red = Redis.new
15 config/initializers/session_store.rb
@@ -0,0 +1,15 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key for verifying cookie session data integrity.
+# If you change this key, all old sessions will become invalid!
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+ActionController::Base.session = {
+ :key => '_schema4less_session',
+ :secret => '2ec5919579fa2ee2c468fb5f19426bf8429c890e269bad7071336345e775fdbc5b45884098b54fb1b6f613832544e81c6f4b484c3d89e503c9428372a10e9450'
+}
+
+# Use the database for sessions instead of the cookie-based default,
+# which shouldn't be used to store highly confidential information
+# (create the session table with "rake db:sessions:create")
+# ActionController::Base.session_store = :active_record_store
41 config/locales/devise.en.yml
@@ -0,0 +1,41 @@
+en:
+ errors:
+ messages:
+ not_found: "not found"
+ already_confirmed: "was already confirmed"
+ not_locked: "was not locked"
+
+ devise:
+ sessions:
+ link: 'Sign in'
+ signed_in: 'Signed in successfully.'
+ signed_out: 'Signed out successfully.'
+ unauthenticated: 'You need to sign in or sign up before continuing.'
+ unconfirmed: 'You have to confirm your account before continuing.'
+ locked: 'Your account is locked.'
+ invalid: 'Invalid email or password.'
+ invalid_token: 'Invalid authentication token.'
+ timeout: 'Your session expired, please sign in again to continue.'
+ inactive: 'Your account was not activated yet.'
+ passwords:
+ link: 'Forgot password?'
+ send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
+ updated: 'Your password was changed successfully. You are now signed in.'
+ confirmations:
+ link: "Didn't receive confirmation instructions?"
+ send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
+ confirmed: 'Your account was successfully confirmed. You are now signed in.'
+ registrations:
+ link: 'Sign up'
+ signed_up: 'You have signed up successfully.'
+ updated: 'You updated your account successfully.'
+ destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
+ unlocks:
+ link: "Didn't receive unlock instructions?"
+ send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
+ unlocked: 'Your account was successfully unlocked. You are now signed in.'
+ mailer:
+ confirmation_instructions: 'Confirmation instructions'
+ reset_password_instructions: 'Reset password instructions'
+ unlock_instructions: 'Unlock Instructions'
+
5 config/locales/en.yml
@@ -0,0 +1,5 @@
+# Sample localization file for English. Add more files in this directory for other locales.
+# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
+
+en:
+ hello: "Hello world"
69 config/routes.rb
@@ -0,0 +1,69 @@
+Schema4less::Application.routes.draw do |map|
+ devise_for :users
+ root :to => 'products#index'
+
+ resources :products do
+ post :purchase, :on => :member
+ end
+
+ resources :users do
+ post :follow, :on => :member
+ end
+
+ # The priority is based upon order of creation:
+ # first created -> highest priority.
+
+ # Sample of regular route:
+ # match 'products/:id' => 'catalog#view'
+ # Keep in mind you can assign values other than :controller and :action
+
+ # Sample of named route:
+ # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
+ # This route can be invoked with purchase_url(:id => product.id)
+
+ # Sample resource route (maps HTTP verbs to controller actions automatically):
+ # resources :products
+
+ # Sample resource route with options:
+ # resources :products do
+ # member do
+ # get :short
+ # post :toggle
+ # end
+ #
+ # collection do
+ # get :sold
+ # end
+ # end
+
+ # Sample resource route with sub-resources:
+ # resources :products do
+ # resources :comments, :sales
+ # resource :seller
+ # end
+
+ # Sample resource route with more complex sub-resources
+ # resources :products do
+ # resources :comments
+ # resources :sales do
+ # get :recent, :on => :collection
+ # end
+ # end
+
+ # Sample resource route within a namespace:
+ # namespace :admin do
+ # # Directs /admin/products/* to Admin::ProductsController
+ # # (app/controllers/admin/products_controller.rb)
+ # resources :products
+ # end
+
+ # You can have the root of your site routed with "root"
+ # just remember to delete public/index.html.
+ # root :to => "welcome#index"
+
+ # See how all your routes lay out with "rake routes"
+
+ # This is a legacy wild controller route that's not recommended for RESTful applications.
+ # Note: This route will make all actions in every controller accessible via GET requests.
+ # match ':controller(/:action(/:id(.:format)))'
+end
19 db/migrate/20100311050013_devise_create_users.rb
@@ -0,0 +1,19 @@
+class DeviseCreateUsers < ActiveRecord::Migration
+ def self.up
+ create_table(:users) do |t|
+ t.string :email
+ t.string :name
+ t.authenticatable :encryptor => :sha1, :null => false
+ t.rememberable
+
+ t.timestamps
+ end
+
+ add_index :users, :email, :unique => true
+ # add_index :users, :unlock_token, :unique => true
+ end
+
+ def self.down
+ drop_table :users
+ end
+end
14 db/migrate/20100311060326_create_purchases.rb
@@ -0,0 +1,14 @@
+class CreatePurchases < ActiveRecord::Migration
+ def self.up
+ create_table :purchases do |t|
+ t.integer :user_id
+ t.string :product_id
+
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :purchases
+ end
+end
34 db/schema.rb
@@ -0,0 +1,34 @@
+# This file is auto-generated from the current state of the database. Instead of editing this file,
+# please use the migrations feature of Active Record to incrementally modify your database, and
+# then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your database schema. If you need
+# to create the application database on another system, you should be using db:schema:load, not running
+# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended to check this file into your version control system.
+
+ActiveRecord::Schema.define(:version => 20100311060326) do
+
+ create_table "purchases", :force => true do |t|
+ t.integer "user_id"
+ t.string "product_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "users", :force => true do |t|
+ t.string "email", :null => false
+ t.string "name"
+ t.string "encrypted_password", :limit => 40, :null => false
+ t.string "password_salt", :null => false
+ t.string "remember_token", :limit => 20
+ t.datetime "remember_created_at"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "users", ["email"], :name => "index_users_on_email", :unique => true
+
+end
7 db/seeds.rb
@@ -0,0 +1,7 @@
+# This file should contain all the record creation needed to seed the database with its default values.
+# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
+#
+# Examples:
+#
+# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
+# Mayor.create(:name => 'Daley', :city => cities.first)
2 doc/README_FOR_APP
@@ -0,0 +1,2 @@
+Use this README file to introduce your application and point to useful places in the API for learning more.
+Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
58 futurama_characters.txt
@@ -0,0 +1,58 @@
+Philip J. Fry
+Turanga Leela
+Bender B. Rodriguez
+Hubert J. Farnsworth
+Zoidberg
+Hermes Conrad
+Amy Wong
+Barbados Slim
+Calculon
+Cubert Farnsworth
+Ogden Wernstrom
+Kif Kroker
+Lrrr
+Mom
+Ignor
+Nibbler
+Richard Nixon
+Turanga Morris
+TurangaMunda
+Zapp Brannigan
+Scruffy
+Al Gore
+Boxy
+Brain Slugs
+Brainspawn
+The Crushinator
+Dwight Conrad
+Father Changstein-El-Gamal
+Elzar
+Flexo
+Gypsy-Bot
+Hattie McDoogal
+Hedonismbot
+Horrible Gelatinous Blob
+Hyperchicken
+Hypnotoad
+Kwanzaabot
+Chanukah Zombie
+LaBarbara Conrad
+Leo and Inez Wong
+Linda
+Malfunctioning Eddy
+Master Phnog
+Michelle
+Morbo
+Panucci
+Nibblonians
+Pazuzu
+Petunia
+Randy
+Reverend Preacherbot
+Roberto
+Robot Devil
+Robot Mafia
+Robot Santa
+Sal
+Smitty
+Tinny Tim
0 lib/tasks/.gitkeep
No changes.
24 lib/tasks/dbs.rake
@@ -0,0 +1,24 @@
+namespace :db do
+ namespace :redis do
+ task :reset => :environment do
+ Red.flush_all
+ puts "-- Redis Reset"
+ end
+ end
+
+ namespace :mongo do
+ task :reset => :environment do
+ MongoMapper.connection.drop_database('schema4less')
+ puts "-- MongoDB Reset"
+ end
+ end
+end
+
+namespace :dbs do
+ desc 'Reset all databases (not just SQL)'
+ task :reset => ['db:reset', 'dbs:nosql:reset']
+
+ namespace :nosql do
+ task :reset => ['db:redis:reset','db:mongo:reset']
+ end
+end
94 lib/tasks/populate.rake
@@ -0,0 +1,94 @@
+task :red_button => ['dbs:reset', 'populate:users', 'populate:amazon:all', 'populate:follow', 'populate:purchase']
+
+namespace :populate do
+ desc 'Create a bunch of superheroes'
+ task :users => :environment do
+ File.open('futurama_characters.txt') do |f|
+ while name = f.gets.strip!
+ u = User.new(
+ :email => name.gsub(/[^a-z0-9_-]/i,'').underscore + '@example.com',
+ :password => 'test',
+ :password_confirmation => 'test'
+ )
+ u.name = name
+ puts " + #{name}" if u.save
+ end
+ end
+ end
+
+ desc 'Have everyone follow some random people.'
+ task :follow => :environment do
+ puts "== Populating Follows..."
+ User.all.each do |u|
+ User.all(:order => "RANDOM()", :limit => (rand(User.count - 10)+10)).each do |f|
+ puts " + #{u.name} is now following #{f.name}" if u.follow!(f)
+ end
+ end
+ end
+
+ desc 'Have everyone buy some random stuff.'
+ task :purchase => :environment do
+ puts "== Populating Purchases..."
+ products = Product.all
+
+ (User.count * 8).times do
+ u = User.first(:order => "RANDOM()")
+ p = products.sort_by{rand}.first
+ puts " + #{u.name} bought #{p.title}" if Purchase.create(:user => u, :product => p)
+ end
+ end
+
+ desc 'populate the database with some books about Ruby'
+ namespace :amazon do
+ task :books => :environment do
+ puts '== Populating Books...'
+
+ for page in 1..4
+ results = Amazon::Ecs.item_search('ruby programming', {:response_group => 'Medium', :sort => 'salesrank', :item_page => page})
+
+ results.items.each do |item|
+ next unless item.get('productgroup') == 'Book'
+ atts = item.get_hash(:itemattributes)
+ Product.create!(
+ :type => atts[:productgroup],
+ :title => atts[:title],
+ :image => item.get('smallimage/url'),
+ :info => {
+ :release_date => Time.parse(atts[:publicationdate]),
+ :author => atts[:author],
+ :pages => atts[:numberofpages],
+ :publisher => atts[:publisher]
+ }
+ )
+ puts " + #{atts[:title]} by #{atts[:author]}"
+ end
+ end
+ end
+
+ task :movies => :environment do
+ puts '== Populating Movies...'
+ for query in %w(batman superman spiderman trek vampires zombies)
+ results = Amazon::Ecs.item_search(query, {:search_index => 'DVD', :response_group => 'Medium', :sort => 'salesrank'})
+
+ results.items.each do |movie|
+ atts = movie.get_hash(:itemattributes)
+ Product.create(
+ :type => 'Movie',
+ :image => movie.get('smallimage/url'),
+ :title => movie.get('title'),
+ :info => {
+ :cast => movie.get_array('actor'),
+ :review => movie.get('editorialreview/content'),
+ :running_time => movie.get('itemattributes/runningtime').to_i
+ }
+ )
+ puts " + #{atts[:title]}"
+ end
+ end
+
+ puts "Total of #{results.total_results} matches"
+ end
+
+ task :all => ['populate:amazon:books', 'populate:amazon:movies']
+ end
+end
26 public/404.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>The page you were looking for doesn't exist (404)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/404.html -->
+ <div class="dialog">
+ <h1>The page you were looking for doesn't exist.</h1>
+ <p>You may have mistyped the address or the page may have moved.</p>
+ </div>
+</body>
+</html>
26 public/422.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>The change you wanted was rejected (422)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/422.html -->
+ <div class="dialog">
+ <h1>The change you wanted was rejected.</h1>
+ <p>Maybe you tried to change something you didn't have access to.</p>
+ </div>
+</body>
+</html>
26 public/500.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>We're sorry, but something went wrong (500)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/500.html -->
+ <div class="dialog">
+ <h1>We're sorry, but something went wrong.</h1>
+ <p>We've been notified about this issue and we'll take a look at it shortly.</p>
+ </div>
+</body>
+</html>
0 public/favicon.ico
No changes.
BIN public/images/rails.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 public/robots.txt
@@ -0,0 +1,5 @@
+# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
+#
+# To ban all spiders from the entire site uncomment the next two lines:
+# User-Agent: *
+# Disallow: /
0 public/stylesheets/.gitkeep
No changes.
181 public/stylesheets/master.css
@@ -0,0 +1,181 @@
+body {
+ font-family: "Museo Sans";
+ color: #333;
+ width: 960px;
+ margin: 0 auto;
+}
+
+a {
+ color: #269;
+}
+
+header, footer, section, nav, aside {
+ display: block;
+}
+
+#top h1 {
+ clear: both;
+ font-size: 60px;
+ text-align: center;
+ color: white;
+ background: #333;
+ margin: 15px 0 0;
+ padding: 25px 20px 20px;
+ -webkit-border-radius: 15px;
+ -webkit-border-bottom-left-radius: 0;
+ -webkit-border-bottom-right-radius: 0;
+ background: -webkit-gradient(linear, 0 0, 0 100%, from(#555), to(#222));
+ -webkit-box-shadow: 0 3px 10px rgba(0,0,0,0.4);
+}
+
+#user-bar {
+ float: right;
+ background: #ffc;
+ padding: 8px 10px 5px;
+ border: 1px solid #aa7;
+ -webkit-border-radius: 5px;
+ margin: 5px 0 10px;
+}
+
+table {
+ -webkit-border-radius: 10px;
+ border: 1px solid #aaa;
+ border-collapse: collapse;
+ margin: 0 auto;
+}
+
+table tr th, table tr td {
+ font-size: 20px;
+ padding: 10px;
+ border-bottom: 1px solid #ccc;
+}
+
+table tr th {
+ vertical-align: top;
+}
+
+#menu {
+ background: -webkit-gradient(linear, 0 0, 0 100%, from(#279), to(#49b));
+ list-style: none;
+ -webkit-border-bottom-left-radius: 8px;
+ -webkit-border-bottom-right-radius: 8px;
+ margin-bottom: 20px;
+}
+
+#menu ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+}
+
+#menu li {
+ display: inline-block;
+ margin: 0;
+ padding: 0;
+}
+
+#menu a {
+ display: block;
+ line-height: 36px;
+ font-size: 20px;
+ color: white;
+ padding: 0 18px;
+ text-decoration: none;
+}
+
+.flash {
+ background: #444;
+ color: white;
+ padding: 8px 10px 5px;
+ -webkit-border-radius: 4px;
+ margin: 20px 0 20px;
+}
+
+.flash ul { list-style: none; margin: 0; padding: 0;}
+
+footer {
+ text-align: center;
+ margin-top: 40px;
+ margin-bottom: 15px;
+ padding: 8px;
+ background: -webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#000));
+ -webkit-border-radius: 10px;
+ color: white;
+}
+
+.sidebar {
+ background: #ffc;
+ float: right;
+ width: 200px;
+ padding: 10px;
+}
+
+.sidebar h1 {
+ font-size: 20px;
+}
+
+ul.notifications {
+ padding: 0;
+ margin: 20px 0;
+ border-bottom: 1px solid #ccc;
+ list-style: none;
+ margin-right: 250px;
+}
+
+ul.notifications li {
+ font-size: 14px;
+ background: white;
+ border: 1px solid #ccc;
+ border-bottom: 0;
+ padding: 5px 10px;
+}
+
+ul.notifications time {
+ float: right;
+ opacity: 0.5;
+ font-size: 12px;
+}
+
+dl { font-size: 14px;}
+dt {
+ float:left;
+ text-align: right;
+ width: 130px;
+ margin-right: 10px;
+ font-weight: bold;
+}
+
+dd {
+ margin-left: 140px;
+}
+
+.social_graph ul {
+ list-style: none;
+ padding: 0;
+ margin: 10px 0;
+}
+
+.social_graph li {
+ display: inline-block;
+ margin-bottom: 3px;
+}
+
+.social_graph li a {
+ display: block;
+ padding: 3px 6px;
+ background: #ddb;
+ color: #333;
+ text-decoration: none;
+ font-size: 12px;
+}
+
+.social_graph li a:hover {
+ background: #eec;
+ color: black;
+}
+
+h1 em {
+ font-size: 0.8em;
+ opacity: 0.6;
+ font-weight: normal;
+ font-style: normal;
+}
10 script/rails
@@ -0,0 +1,10 @@
+#!/usr/bin/env ruby
+# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
+
+ENV_PATH = File.expand_path('../../config/environment', __FILE__)
+BOOT_PATH = File.expand_path('../../config/boot', __FILE__)
+APP_PATH = File.expand_path('../../config/application', __FILE__)
+ROOT_PATH = File.expand_path('../..', __FILE__)
+
+require BOOT_PATH
+require 'rails/commands'
450 superhero_names.txt
@@ -0,0 +1,450 @@
+Abbess
+Ablaze
+Ace
+Acid
+Adamant
+Aegis
+Airspeed
+Alaczar
+AlleyCat
+Animus
+Anti-Matter Man
+Aqualung
+Arc
+ArchAngel
+Argus
+Armadillo
+Arsenal
+Asmodeus
+Astra
+Atomaestro
+Avion
+Axe
+BackFlash
+Badger
+Ballistique
+Banelord
+Baron K
+Barracuda
+Basalt
+Battery
+Bile
+Billy Blue Blazes
+Bird of Prey
+Black Adept
+Blackbody
+Black Falcon
+Black Light
+Blackmane
+BlackShadow
+Blackthorne
+Black Wolf
+Blade Song
+Blast Off
+Bloodletter
+Bloodstone
+Bloodsword
+Blood Warrior
+Bludgeon
+Blue Raider
+Brain Child
+Brain Damage
+Brain Freeze
+Brainstorm
+Briquette
+Bruja
+Buck Skin
+Bull
+Bulle
+Bullet
+Cacophony
+Calico
+Captain Combat
+Captain Gorilla
+Cat Lord
+Celcius
+Chameleon
+Chaos Hawk
+Charmer
+Checkmate
+Chill
+Chrome
+Cinnamon Girl
+Citius
+Concussion
+Condor
+Core Commander
+Cortex
+Cosmos
+Crimebuster
+Crimson Advenger
+Crossfire
+Damask
+Darkchilde
+Dark Elf
+Darkhail
+DarkKnight
+Dayglo
+Deathbolt
+Death Metal
+Deathsong
+Decibelle
+Der Eisenwolf
+Dervish
+Destructeur
+Detonator
+Diamond Jim
+Diana
+Domino
+Downsizer
+Dr. Power
+Dune
+Dusk
+Dwindler
+Eagle Eye
+Eclipse
+Edge
+Elastique
+Elementalist
+Elf
+Eliminator
+Elusive Butterfly
+Eradicator
+Erg
+Express
+Eye Tyrant
+Falcon
+F.A.S.T.
+Farseer
+Feedback
+Felina
+Felon
+Firefall
+Firefight
+FireFly
+Flame
+Flashback
+Flower Child
+Fly Girl
+Force
+Fracas
+Freak-Out
+Frenzy
+Frequent Flyer
+Frost
+Frostbite
+Fuhrer
+Fuji
+Gargoyle
+Gauntlet
+Geistmeister
+Gemini
+Genocide
+Ghost Girl
+Giggler
+Glitter
+Golden Eagle II
+Golden Girl
+Gothyk
+Green Dragon
+Grenadier
+Grido
+GrimKaiser
+Ground Zero
+Guillotine
+Hammer
+Hammer of God
+Hardcase
+Harlequin
+Headbanger
+Headhunter
+Heavy Metal
+Hellfire
+Hellrazor
+Hemlok
+Herr Krebs
+Hitman
+Holocaust
+Hornet
+Hunter-Killer
+Ice Fury
+Ice Storm
+Imagine
+Impostor
+Incandesca
+Incendie
+Inferno
+Infinity
+Intuition
+Iron Mask
+Jackdaw
+Javelin
+Jester
+Kane
+Kibosh
+Krieger
+Kriegspeil
+Kutter
+Ladykiller
+Lady Marmalade
+Lady Steele
+Lady Willpower
+Lenz
+Lichtstrahl
+Lilith
+Lithos
+Lone Star
+Long Horn
+Mach 5
+Machete
+Macro
+Magnifico
+Mandrake
+Manslaughter
+Man-Spider
+Martinet
+Material Girl
+Matte Black
+Mean Mr. Mustard
+Mecha
+Mechanon
+Megalith
+Megavolt
+Mentalita
+Merc
+Merry-Andrew
+Mind Blade
+Mind Flayer
+Minus
+Minx
+Mist Demon
+Mollock the Eater of Children
+Monsier Diamont
+Moonshooter
+Moonstone
+Mr. Otto
+Mr. Peppermint Man
+Mr. Soul
+Mr. Zero
+Multipleman
+Myriad
+Napalm
+Nefario
+Negatron
+Nemesis
+Neurosis
+Nightengale
+Night Racer
+Nightshifter
+Nightstrike
+Nightswift
+Nuetron Star
+Nukewarm
+Oberon
+Olympia
+Operative
+Overdrive
+Overkill
+Pacificateur
+Paladin
+Panzer
+Paragon
+Parasite
+Parsec
+Particle Man
+Phantom Woman
+Phaze
+Photon
+Portal
+Powerhouse
+Power Princess
+Predator
+Prism
+Proletarian
+Prowler
+Psi-Borg
+Psifire
+Psi Mistress
+Psion
+Psychedelic
+Psyke-Out
+Psy-kill
+Pulsar
+Purple Haze
+Pyre
+Quad
+Quadrant
+QuickSilver
+Radioactive Man
+Rage
+Rampager
+Random
+Raptor
+Reaver
+Recoil
+Red Baron
+Red Devil
+Redline
+Red Lion
+Red Rajah
+Red Spectrum
+Reflex
+Replay
+Restart
+Retribution
+Revenant
+Reverie
+Rhino
+Ringmaster
+Ripclaw
+Rose
+Rosetta
+Roulette
+Rubberband Man
+Ruckus
+Sable
+SabreHawk
+Sahara
+Salvo
+Sandstorm
+Sargon
+Savante
+Savateuse
+Scari
+Scarlet Canary
+Scathe
+Screaming Hawk
+Seizure
+Seker
+Serephena
+Seventh Son
+Sgt Steel
+Shadow Dancer
+ShadowMaster
+Shadow Queen
+Shadowscan
+Shadow Stalker
+Shadowsword
+Shadowweaver
+Shaman
+Shapeless
+Shard
+Sharpshooter
+Shatter
+She Cat
+Shiver
+Shockwave
+Shooting Star
+Shrapnel
+Silk Spider
+Silverblade
+Silverfox
+Silvershield
+Silversiren
+Silver Stilleto
+Silverstone
+Silverstreak
+Silverswift
+Siphon