├── .autotest ├── .gitignore ├── .rspec ├── Gemfile ├── Gemfile.lock ├── README.markdown ├── Rakefile ├── app ├── controllers │ ├── application_controller.rb │ ├── microposts_controller.rb │ ├── pages_controller.rb │ ├── relationships_controller.rb │ ├── sessions_controller.rb │ └── users_controller.rb ├── helpers │ ├── application_helper.rb │ ├── microposts_helper.rb │ ├── pages_helper.rb │ ├── sessions_helper.rb │ └── users_helper.rb ├── models │ ├── micropost.rb │ ├── relationship.rb │ └── user.rb └── views │ ├── layouts │ ├── _footer.html.erb │ ├── _header.html.erb │ ├── _stylesheets.html.erb │ └── application.html.erb │ ├── microposts │ └── _micropost.html.erb │ ├── pages │ ├── about.html.erb │ ├── contact.html.erb │ ├── help.html.erb │ └── home.html.erb │ ├── relationships │ ├── create.js.erb │ └── destroy.js.erb │ ├── sessions │ └── new.html.erb │ ├── shared │ ├── _error_messages.html.erb │ ├── _feed.html.erb │ ├── _feed_item.html.erb │ ├── _micropost_form.html.erb │ ├── _stats.html.erb │ └── _user_info.html.erb │ └── users │ ├── _fields.html.erb │ ├── _follow.html.erb │ ├── _follow_form.html.erb │ ├── _unfollow.html.erb │ ├── _user.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ ├── show.html.erb │ └── show_follow.html.erb ├── autotest └── discover.rb ├── bin ├── annotate ├── autospec ├── autotest ├── erubis ├── htmldiff ├── ldiff ├── multigem ├── multiruby ├── multiruby_setup ├── nokogiri ├── rackup ├── rails ├── rake ├── rake2thor ├── rdoc ├── ri ├── rspec ├── spork ├── thor ├── tt ├── unit_diff └── zentest ├── bundler_stubs ├── annotate ├── autospec ├── erubis ├── htmldiff ├── ldiff ├── nokogiri ├── rackup ├── rails ├── rake ├── rake2thor ├── rdoc ├── ri ├── rspec ├── spork ├── thor └── tt ├── config.ru ├── config ├── application.rb ├── boot.rb ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── backtrace_silencers.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── secret_token.rb │ └── session_store.rb ├── locales │ └── en.yml └── routes.rb ├── db ├── migrate │ ├── 20100821203213_create_users.rb │ ├── 20100822012431_add_email_uniqueness_index.rb │ ├── 20100822204528_add_password_to_users.rb │ ├── 20100822233125_add_salt_to_users.rb │ ├── 20100829021049_add_admin_to_users.rb │ ├── 20100829210229_create_microposts.rb │ └── 20100831012055_create_relationships.rb ├── schema.rb └── seeds.rb ├── doc └── README_FOR_APP ├── lib └── tasks │ ├── .gitkeep │ └── sample_data.rake ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico ├── images │ ├── logo.png │ └── rails.png ├── javascripts │ ├── application.js │ ├── controls.js │ ├── dragdrop.js │ ├── effects.js │ ├── prototype.js │ └── rails.js ├── robots.txt └── stylesheets │ ├── .gitkeep │ ├── blueprint │ ├── ie.css │ ├── plugins │ │ ├── buttons │ │ │ ├── icons │ │ │ │ ├── cross.png │ │ │ │ ├── key.png │ │ │ │ └── tick.png │ │ │ ├── readme.txt │ │ │ └── screen.css │ │ ├── fancy-type │ │ │ ├── readme.txt │ │ │ └── screen.css │ │ ├── link-icons │ │ │ ├── icons │ │ │ │ ├── doc.png │ │ │ │ ├── email.png │ │ │ │ ├── external.png │ │ │ │ ├── feed.png │ │ │ │ ├── im.png │ │ │ │ ├── pdf.png │ │ │ │ ├── visited.png │ │ │ │ └── xls.png │ │ │ ├── readme.txt │ │ │ └── screen.css │ │ └── rtl │ │ │ ├── readme.txt │ │ │ └── screen.css │ ├── print.css │ ├── screen.css │ └── src │ │ ├── forms.css │ │ ├── grid.css │ │ ├── grid.png │ │ ├── ie.css │ │ ├── print.css │ │ ├── reset.css │ │ └── typography.css │ └── custom.css ├── script └── rails ├── spec ├── controllers │ ├── microposts_controller_spec.rb │ ├── pages_controller_spec.rb │ ├── relationships_controller_spec.rb │ ├── sessions_controller_spec.rb │ └── users_controller_spec.rb ├── factories.rb ├── models │ ├── micropost_spec.rb │ ├── relationship_spec.rb │ └── user_spec.rb ├── requests │ ├── friendly_forwardings_spec.rb │ ├── layout_links_spec.rb │ ├── microposts_spec.rb │ └── users_spec.rb └── spec_helper.rb └── vendor └── plugins └── .gitkeep /.autotest: -------------------------------------------------------------------------------- 1 | require 'autotest/growl' 2 | require 'autotest/fsevent' 3 | 4 | Autotest.add_hook :initialize do |autotest| 5 | autotest.add_mapping(/^spec\/requests\/.*_spec\.rb$/) do 6 | autotest.files_matching(/^spec\/requests\/.*_spec\.rb$/) 7 | end 8 | end -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | db/*.sqlite3* 3 | log/*.log 4 | *.log 5 | /tmp/ 6 | doc/ 7 | *.swp 8 | *~ 9 | .project 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --colour 2 | --drb 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'rails', '3.0.12' 4 | gem 'gravatar_image_tag', '1.0.0.pre2' 5 | gem 'will_paginate', '3.0.pre2' 6 | gem 'sqlite3', '1.3.4' 7 | 8 | group :development do 9 | gem 'rspec-rails', '2.6.1' 10 | gem 'annotate', '2.4.0' 11 | gem 'faker', '0.3.1' 12 | end 13 | 14 | group :test do 15 | gem 'rspec-rails', '2.6.1' 16 | gem 'webrat', '0.7.1' 17 | gem 'spork', '0.9.0.rc8' 18 | gem 'factory_girl_rails', '1.0' 19 | # gem 'autotest', '4.4.6' 20 | # gem 'autotest-rails-pure', '4.1.2' 21 | # gem 'autotest-fsevent', '0.2.4' 22 | # gem 'autotest-growl', '0.2.9' 23 | end 24 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | abstract (1.0.0) 5 | actionmailer (3.0.12) 6 | actionpack (= 3.0.12) 7 | mail (~> 2.2.19) 8 | actionpack (3.0.12) 9 | activemodel (= 3.0.12) 10 | activesupport (= 3.0.12) 11 | builder (~> 2.1.2) 12 | erubis (~> 2.6.6) 13 | i18n (~> 0.5.0) 14 | rack (~> 1.2.5) 15 | rack-mount (~> 0.6.14) 16 | rack-test (~> 0.5.7) 17 | tzinfo (~> 0.3.23) 18 | activemodel (3.0.12) 19 | activesupport (= 3.0.12) 20 | builder (~> 2.1.2) 21 | i18n (~> 0.5.0) 22 | activerecord (3.0.12) 23 | activemodel (= 3.0.12) 24 | activesupport (= 3.0.12) 25 | arel (~> 2.0.10) 26 | tzinfo (~> 0.3.23) 27 | activeresource (3.0.12) 28 | activemodel (= 3.0.12) 29 | activesupport (= 3.0.12) 30 | activesupport (3.0.12) 31 | annotate (2.4.0) 32 | arel (2.0.10) 33 | builder (2.1.2) 34 | diff-lcs (1.1.2) 35 | erubis (2.6.6) 36 | abstract (>= 1.0.0) 37 | factory_girl (1.3.3) 38 | factory_girl_rails (1.0) 39 | factory_girl (~> 1.3) 40 | rails (>= 3.0.0.beta4) 41 | faker (0.3.1) 42 | gravatar_image_tag (1.0.0.pre2) 43 | i18n (0.5.0) 44 | json (1.6.6) 45 | mail (2.2.19) 46 | activesupport (>= 2.3.6) 47 | i18n (>= 0.4.0) 48 | mime-types (~> 1.16) 49 | treetop (~> 1.4.8) 50 | mime-types (1.18) 51 | nokogiri (1.4.4) 52 | polyglot (0.3.3) 53 | rack (1.2.5) 54 | rack-mount (0.6.14) 55 | rack (>= 1.0.0) 56 | rack-test (0.5.7) 57 | rack (>= 1.0) 58 | rails (3.0.12) 59 | actionmailer (= 3.0.12) 60 | actionpack (= 3.0.12) 61 | activerecord (= 3.0.12) 62 | activeresource (= 3.0.12) 63 | activesupport (= 3.0.12) 64 | bundler (~> 1.0) 65 | railties (= 3.0.12) 66 | railties (3.0.12) 67 | actionpack (= 3.0.12) 68 | activesupport (= 3.0.12) 69 | rake (>= 0.8.7) 70 | rdoc (~> 3.4) 71 | thor (~> 0.14.4) 72 | rake (0.9.2.2) 73 | rdoc (3.12) 74 | json (~> 1.4) 75 | rspec (2.6.0) 76 | rspec-core (~> 2.6.0) 77 | rspec-expectations (~> 2.6.0) 78 | rspec-mocks (~> 2.6.0) 79 | rspec-core (2.6.4) 80 | rspec-expectations (2.6.0) 81 | diff-lcs (~> 1.1.2) 82 | rspec-mocks (2.6.0) 83 | rspec-rails (2.6.1) 84 | actionpack (~> 3.0) 85 | activesupport (~> 3.0) 86 | railties (~> 3.0) 87 | rspec (~> 2.6.0) 88 | spork (0.9.0.rc8) 89 | sqlite3 (1.3.4) 90 | thor (0.14.6) 91 | treetop (1.4.10) 92 | polyglot 93 | polyglot (>= 0.3.1) 94 | tzinfo (0.3.32) 95 | webrat (0.7.1) 96 | nokogiri (>= 1.2.0) 97 | rack (>= 1.0) 98 | rack-test (>= 0.5.3) 99 | will_paginate (3.0.pre2) 100 | 101 | PLATFORMS 102 | ruby 103 | 104 | DEPENDENCIES 105 | annotate (= 2.4.0) 106 | factory_girl_rails (= 1.0) 107 | faker (= 0.3.1) 108 | gravatar_image_tag (= 1.0.0.pre2) 109 | rails (= 3.0.12) 110 | rspec-rails (= 2.6.1) 111 | spork (= 0.9.0.rc8) 112 | sqlite3 (= 1.3.4) 113 | webrat (= 0.7.1) 114 | will_paginate (= 3.0.pre2) 115 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Ruby on Rails Tutorial: sample application 2 | 3 | **NOTE: This repository is out of date.** 4 | 5 | Go to the [Rails Tutorial Help Page](https://www.railstutorial.org/help) to get a link to the latest version of the Rails Tutorial sample app. 6 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 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 | require 'rake' 6 | 7 | SampleApp::Application.load_tasks 8 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | include SessionsHelper 4 | end 5 | -------------------------------------------------------------------------------- /app/controllers/microposts_controller.rb: -------------------------------------------------------------------------------- 1 | class MicropostsController < ApplicationController 2 | before_filter :authenticate 3 | before_filter :authorized_user, :only => :destroy 4 | 5 | def create 6 | @micropost = current_user.microposts.build(params[:micropost]) 7 | if @micropost.save 8 | redirect_to root_path, :flash => { :success => "Micropost created!" } 9 | else 10 | @feed_items = [] 11 | render 'pages/home' 12 | end 13 | end 14 | 15 | def destroy 16 | @micropost.destroy 17 | redirect_to root_path, :flash => { :success => "Micropost deleted!" } 18 | end 19 | 20 | private 21 | 22 | def authorized_user 23 | @micropost = current_user.microposts.find_by_id(params[:id]) 24 | redirect_to root_path if @micropost.nil? 25 | end 26 | end -------------------------------------------------------------------------------- /app/controllers/pages_controller.rb: -------------------------------------------------------------------------------- 1 | class PagesController < ApplicationController 2 | 3 | def home 4 | @title = "Home" 5 | if signed_in? 6 | @micropost = Micropost.new 7 | @feed_items = current_user.feed.paginate(:page => params[:page]) 8 | end 9 | end 10 | 11 | def contact 12 | @title = "Contact" 13 | end 14 | 15 | def about 16 | @title = "About" 17 | end 18 | 19 | def help 20 | @title = "Help" 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/controllers/relationships_controller.rb: -------------------------------------------------------------------------------- 1 | class RelationshipsController < ApplicationController 2 | before_filter :authenticate 3 | 4 | def create 5 | @user = User.find(params[:relationship][:followed_id]) 6 | current_user.follow!(@user) 7 | respond_to do |format| 8 | format.html { redirect_to @user } 9 | format.js 10 | end 11 | end 12 | 13 | def destroy 14 | @user = Relationship.find(params[:id]).followed 15 | current_user.unfollow!(@user) 16 | respond_to do |format| 17 | format.html { redirect_to @user } 18 | format.js 19 | end 20 | end 21 | end -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < ApplicationController 2 | 3 | def new 4 | @title = "Sign in" 5 | end 6 | 7 | def create 8 | user = User.authenticate(params[:session][:email], 9 | params[:session][:password]) 10 | if user.nil? 11 | flash.now[:error] = "Invalid email/password combination." 12 | @title = "Sign in" 13 | render 'new' 14 | else 15 | sign_in user 16 | redirect_back_or user 17 | end 18 | end 19 | 20 | def destroy 21 | sign_out 22 | redirect_to root_path 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | before_filter :authenticate, 3 | :only => [:index, :edit, :update, :destroy, 4 | :followers, :following] 5 | before_filter :correct_user, :only => [:edit, :update] 6 | before_filter :admin_user, :only => :destroy 7 | 8 | def index 9 | @users = User.paginate(:page => params[:page]) 10 | @title = "All users" 11 | end 12 | 13 | def show 14 | @user = User.find(params[:id]) 15 | @microposts = @user.microposts.paginate(:page => params[:page]) 16 | @title = @user.name 17 | end 18 | 19 | def following 20 | @title = "Following" 21 | @user = User.find(params[:id]) 22 | @users = @user.following.paginate(:page => params[:page]) 23 | render 'show_follow' 24 | end 25 | 26 | def followers 27 | @title = "Followers" 28 | @user = User.find(params[:id]) 29 | @users = @user.followers.paginate(:page => params[:page]) 30 | render 'show_follow' 31 | end 32 | 33 | def new 34 | @user = User.new 35 | @title = "Sign up" 36 | end 37 | 38 | def create 39 | @user = User.new(params[:user]) 40 | if @user.save 41 | sign_in @user 42 | redirect_to @user, :flash => { :success => "Welcome to the Sample App!" } 43 | else 44 | @title = "Sign up" 45 | render 'new' 46 | end 47 | end 48 | 49 | def edit 50 | @title = "Edit user" 51 | end 52 | 53 | def update 54 | if @user.update_attributes(params[:user]) 55 | redirect_to @user, :flash => { :success => "Profile updated." } 56 | else 57 | @title = "Edit user" 58 | render 'edit' 59 | end 60 | end 61 | 62 | def destroy 63 | @user.destroy 64 | redirect_to users_path, :flash => { :success => "User destroyed." } 65 | end 66 | 67 | private 68 | 69 | def correct_user 70 | @user = User.find(params[:id]) 71 | redirect_to(root_path) unless current_user?(@user) 72 | end 73 | 74 | def admin_user 75 | @user = User.find(params[:id]) 76 | redirect_to(root_path) if !current_user.admin? || current_user?(@user) 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | 3 | # Return a title on a per-page basis. 4 | def title 5 | base_title = "Ruby on Rails Tutorial Sample App" 6 | if @title.nil? 7 | base_title 8 | else 9 | "#{base_title} | #{@title}" 10 | end 11 | end 12 | 13 | def logo 14 | image_tag("logo.png", :alt => "Sample App", :class => "round") 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/helpers/microposts_helper.rb: -------------------------------------------------------------------------------- 1 | module MicropostsHelper 2 | 3 | def wrap(content) 4 | sanitize(raw(content.split.map{ |s| wrap_long_string(s) }.join(' '))) 5 | end 6 | 7 | private 8 | 9 | def wrap_long_string(text, max_width = 30) 10 | zero_width_space = "​" 11 | regex = /.{1,#{max_width}}/ 12 | (text.length < max_width) ? text : 13 | text.scan(regex).join(zero_width_space) 14 | end 15 | end -------------------------------------------------------------------------------- /app/helpers/pages_helper.rb: -------------------------------------------------------------------------------- 1 | module PagesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/sessions_helper.rb: -------------------------------------------------------------------------------- 1 | module SessionsHelper 2 | 3 | def sign_in(user) 4 | cookies.permanent.signed[:remember_token] = [user.id, user.salt] 5 | self.current_user = user 6 | end 7 | 8 | def current_user=(user) 9 | @current_user = user 10 | end 11 | 12 | def current_user 13 | @current_user ||= user_from_remember_token 14 | end 15 | 16 | def signed_in? 17 | !current_user.nil? 18 | end 19 | 20 | def sign_out 21 | cookies.delete(:remember_token) 22 | self.current_user = nil 23 | end 24 | 25 | def current_user?(user) 26 | user == current_user 27 | end 28 | 29 | def authenticate 30 | deny_access unless signed_in? 31 | end 32 | 33 | def deny_access 34 | store_location 35 | redirect_to signin_path, :notice => "Please sign in to access this page." 36 | end 37 | 38 | def redirect_back_or(default) 39 | redirect_to(session[:return_to] || default) 40 | clear_return_to 41 | end 42 | 43 | private 44 | 45 | def user_from_remember_token 46 | User.authenticate_with_salt(*remember_token) 47 | end 48 | 49 | def remember_token 50 | cookies.signed[:remember_token] || [nil, nil] 51 | end 52 | 53 | def store_location 54 | session[:return_to] = request.fullpath 55 | end 56 | 57 | def clear_return_to 58 | session[:return_to] = nil 59 | end 60 | end 61 | 62 | -------------------------------------------------------------------------------- /app/helpers/users_helper.rb: -------------------------------------------------------------------------------- 1 | module UsersHelper 2 | def gravatar_for(user, options = { :size => 50 }) 3 | gravatar_image_tag(user.email.downcase, :alt => h(user.name), 4 | :class => 'gravatar', 5 | :gravatar => options) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/models/micropost.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # Schema version: 20100829210229 3 | # 4 | # Table name: microposts 5 | # 6 | # id :integer not null, primary key 7 | # content :string(255) 8 | # user_id :integer 9 | # created_at :datetime 10 | # updated_at :datetime 11 | # 12 | 13 | class Micropost < ActiveRecord::Base 14 | attr_accessible :content 15 | 16 | belongs_to :user 17 | 18 | validates :content, :presence => true, :length => { :maximum => 140 } 19 | validates :user_id, :presence => true 20 | 21 | default_scope :order => 'microposts.created_at DESC' 22 | 23 | scope :from_users_followed_by, lambda { |user| followed_by(user) } 24 | 25 | private 26 | 27 | def self.followed_by(user) 28 | following_ids = %(SELECT followed_id FROM relationships 29 | WHERE follower_id = :user_id) 30 | where("user_id IN (#{following_ids}) OR user_id = :user_id", 31 | :user_id => user) 32 | end 33 | end -------------------------------------------------------------------------------- /app/models/relationship.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # Schema version: 20100831012055 3 | # 4 | # Table name: relationships 5 | # 6 | # id :integer not null, primary key 7 | # follower_id :integer 8 | # followed_id :integer 9 | # created_at :datetime 10 | # updated_at :datetime 11 | # 12 | 13 | class Relationship < ActiveRecord::Base 14 | attr_accessible :followed_id 15 | 16 | belongs_to :follower, :class_name => "User" 17 | belongs_to :followed, :class_name => "User" 18 | 19 | validates :follower_id, :presence => true 20 | validates :followed_id, :presence => true 21 | end 22 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # Schema version: 20100829021049 3 | # 4 | # Table name: users 5 | # 6 | # id :integer not null, primary key 7 | # name :string(255) 8 | # email :string(255) 9 | # created_at :datetime 10 | # updated_at :datetime 11 | # encrypted_password :string(255) 12 | # salt :string(255) 13 | # admin :boolean 14 | # 15 | 16 | class User < ActiveRecord::Base 17 | attr_accessor :password 18 | attr_accessible :name, :email, :password, :password_confirmation 19 | 20 | has_many :microposts, :dependent => :destroy 21 | has_many :relationships, :dependent => :destroy, 22 | :foreign_key => "follower_id" 23 | has_many :reverse_relationships, :dependent => :destroy, 24 | :foreign_key => "followed_id", 25 | :class_name => "Relationship" 26 | has_many :following, :through => :relationships, :source => :followed 27 | has_many :followers, :through => :reverse_relationships, 28 | :source => :follower 29 | 30 | email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i 31 | 32 | validates :name, :presence => true, 33 | :length => { :maximum => 50 } 34 | validates :email, :presence => true, 35 | :format => { :with => email_regex }, 36 | :uniqueness => { :case_sensitive => false } 37 | validates :password, :presence => true, 38 | :confirmation => true, 39 | :length => { :within => 6..40 } 40 | 41 | before_save :encrypt_password 42 | 43 | def has_password?(submitted_password) 44 | encrypted_password == encrypt(submitted_password) 45 | end 46 | 47 | def feed 48 | Micropost.from_users_followed_by(self) 49 | end 50 | 51 | def following?(followed) 52 | relationships.find_by_followed_id(followed) 53 | end 54 | 55 | def follow!(followed) 56 | relationships.create!(:followed_id => followed.id) 57 | end 58 | 59 | def unfollow!(followed) 60 | relationships.find_by_followed_id(followed).destroy 61 | end 62 | 63 | class << self 64 | def authenticate(email, submitted_password) 65 | user = find_by_email(email) 66 | (user && user.has_password?(submitted_password)) ? user : nil 67 | end 68 | 69 | def authenticate_with_salt(id, cookie_salt) 70 | user = find_by_id(id) 71 | (user && user.salt == cookie_salt) ? user : nil 72 | end 73 | end 74 | 75 | private 76 | 77 | def encrypt_password 78 | self.salt = make_salt unless has_password?(password) 79 | self.encrypted_password = encrypt(password) 80 | end 81 | 82 | def encrypt(string) 83 | secure_hash("#{salt}--#{string}") 84 | end 85 | 86 | def make_salt 87 | secure_hash("#{Time.now.utc}--#{password}") 88 | end 89 | 90 | def secure_hash(string) 91 | Digest::SHA2.hexdigest(string) 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /app/views/layouts/_footer.html.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/layouts/_header.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= link_to logo, root_path %> 3 | 19 |
-------------------------------------------------------------------------------- /app/views/layouts/_stylesheets.html.erb: -------------------------------------------------------------------------------- 1 | 4 | <%= stylesheet_link_tag 'blueprint/screen', :media => 'screen' %> 5 | <%= stylesheet_link_tag 'blueprint/print', :media => 'print' %> 6 | 7 | <%= stylesheet_link_tag 'custom', :media => 'screen' %> -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= title %> 5 | <%= csrf_meta_tag %> 6 | <%= render 'layouts/stylesheets' %> 7 | <%= javascript_include_tag :defaults %> 8 | 9 | 10 |
11 | <%= render 'layouts/header' %> 12 |
13 | <% flash.each do |key, value| %> 14 |
<%= value %>
15 | <% end %> 16 | <%= yield %> 17 |
18 | <%= render 'layouts/footer' %> 19 | <%= debug(params) if Rails.env.development? %> 20 |
21 | 22 | -------------------------------------------------------------------------------- /app/views/microposts/_micropost.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= micropost.content %> 4 | 5 | Posted <%= time_ago_in_words(micropost.created_at) %> ago. 6 | 7 | 8 | <% user = micropost.user rescue User.find(micropost.user_id) %> 9 | <% if current_user?(user) %> 10 | 11 | <%= link_to "delete", micropost, :method => :delete, 12 | :confirm => "You sure?", 13 | :title => micropost.content %> 14 | 15 | <% end %> 16 | -------------------------------------------------------------------------------- /app/views/pages/about.html.erb: -------------------------------------------------------------------------------- 1 |

About Us

2 |

3 | Ruby on Rails Tutorial 4 | is a project to make a book and screencasts to teach web development 5 | with Ruby on Rails. This 6 | is the sample application for the tutorial. 7 |

8 | -------------------------------------------------------------------------------- /app/views/pages/contact.html.erb: -------------------------------------------------------------------------------- 1 |

Contact

2 |

3 | Contact Ruby on Rails Tutorial about the sample app at the 4 | feedback page. 5 |

6 | -------------------------------------------------------------------------------- /app/views/pages/help.html.erb: -------------------------------------------------------------------------------- 1 |

Help

2 |

3 | Get help on Ruby on Rails Tutorial at the 4 | Rails Tutorial help page. 5 | To get help on this sample app, see the 6 | Rails Tutorial book. 7 |

8 | -------------------------------------------------------------------------------- /app/views/pages/home.html.erb: -------------------------------------------------------------------------------- 1 | <% if signed_in? %> 2 | 3 | 4 | 5 | 10 | 14 | 15 |
6 |

What's up?

7 | <%= render 'shared/micropost_form' %> 8 | <%= render 'shared/feed' %> 9 |
16 | 17 | <% else %> 18 | 19 |

Sample App

20 |

21 | This is the home page for the Ruby on Rails Tutorial sample application. 22 |

23 | 24 | <%= link_to "Sign up now!", signup_path, :class => "signup_button round" %> 25 | 26 | <% end %> -------------------------------------------------------------------------------- /app/views/relationships/create.js.erb: -------------------------------------------------------------------------------- 1 | $("follow_form").update("<%= escape_javascript(render('users/unfollow')) %>") 2 | $("followers").update('<%= "#{@user.followers.count} followers" %>') -------------------------------------------------------------------------------- /app/views/relationships/destroy.js.erb: -------------------------------------------------------------------------------- 1 | $("follow_form").update("<%= escape_javascript(render('users/follow')) %>") 2 | $("followers").update('<%= "#{@user.followers.count} followers" %>') -------------------------------------------------------------------------------- /app/views/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 |

Sign in

2 | 3 | <%= form_for(:session, :url => sessions_path) do |f| %> 4 |
5 | <%= f.label :email %>
6 | <%= f.text_field :email %> 7 |
8 |
9 | <%= f.label :password %>
10 | <%= f.password_field :password %> 11 |
12 |
13 | <%= f.submit "Sign in" %> 14 |
15 | <% end %> 16 | 17 |

New user? <%= link_to "Sign up now!", signup_path %>

-------------------------------------------------------------------------------- /app/views/shared/_error_messages.html.erb: -------------------------------------------------------------------------------- 1 | <% if object.errors.any? %> 2 |
3 |

4 | <%= pluralize(object.errors.count, "error") %> 5 | prohibited this <%= object.class.to_s.underscore.humanize.downcase %> 6 | from being saved: 7 |

8 |

There were problems with the following fields:

9 | 14 |
15 | 16 | <% end %> -------------------------------------------------------------------------------- /app/views/shared/_feed.html.erb: -------------------------------------------------------------------------------- 1 | <% if @feed_items.any? %> 2 | 3 | <%= render :partial => 'shared/feed_item', :collection => @feed_items %> 4 |
5 | <%= will_paginate @feed_items %> 6 | <% end %> -------------------------------------------------------------------------------- /app/views/shared/_feed_item.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= link_to gravatar_for(feed_item.user), feed_item.user %> 4 | 5 | 6 | 7 | <%= link_to feed_item.user.name, feed_item.user %> 8 | 9 | <%= wrap(feed_item.content) %> 10 | 11 | Posted <%= time_ago_in_words(feed_item.created_at) %> ago. 12 | 13 | 14 | <% if current_user?(feed_item.user) %> 15 | 16 | <%= link_to "delete", feed_item, :method => :delete, 17 | :confirm => "You sure?", 18 | :title => feed_item.content %> 19 | 20 | <% end %> 21 | -------------------------------------------------------------------------------- /app/views/shared/_micropost_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for(@micropost) do |f| %> 2 | <%= render 'shared/error_messages', :object => f.object %> 3 |
4 | <%= f.text_area :content %> 5 |
6 |
7 | <%= f.submit "Submit" %> 8 |
9 | <% end %> -------------------------------------------------------------------------------- /app/views/shared/_stats.html.erb: -------------------------------------------------------------------------------- 1 | <% @user ||= current_user %> 2 |
3 | 4 | 5 | 12 | 19 | 20 |
6 | 7 | 8 | <%= @user.following.count %> following 9 | 10 | 11 | 13 | 14 | 15 | <%= pluralize(@user.followers.count, "follower") %> 16 | 17 | 18 |
21 |
-------------------------------------------------------------------------------- /app/views/shared/_user_info.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 | <%= gravatar_for current_user, :size => 30 %> 4 | 5 | <%= current_user.name %> 6 | 7 | 8 | <%= pluralize(current_user.microposts.count, "micropost") %> 9 | 10 | 11 |
-------------------------------------------------------------------------------- /app/views/users/_fields.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= f.label :name %>
3 | <%= f.text_field :name %> 4 |
5 |
6 | <%= f.label :email %>
7 | <%= f.text_field :email %> 8 |
9 |
10 | <%= f.label :password %>
11 | <%= f.password_field :password %> 12 |
13 |
14 | <%= f.label :password_confirmation, "Confirmation" %>
15 | <%= f.password_field :password_confirmation %> 16 |
-------------------------------------------------------------------------------- /app/views/users/_follow.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for(current_user.relationships. 2 | build(:followed_id => @user.id), 3 | :remote => true) do |f| %> 4 |
<%= f.hidden_field :followed_id %>
5 |
<%= f.submit "Follow" %>
6 | <% end %> -------------------------------------------------------------------------------- /app/views/users/_follow_form.html.erb: -------------------------------------------------------------------------------- 1 | <% unless current_user?(@user) %> 2 |
3 | <% if current_user.following?(@user) %> 4 | <%= render 'unfollow' %> 5 | <% else %> 6 | <%= render 'follow' %> 7 | <% end %> 8 |
9 | <% end %> -------------------------------------------------------------------------------- /app/views/users/_unfollow.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for(current_user.relationships.find_by_followed_id(@user), 2 | :html => { :method => :delete }, 3 | :remote => true) do |f| %> 4 |
<%= f.submit "Unfollow" %>
5 | <% end %> -------------------------------------------------------------------------------- /app/views/users/_user.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | <%= gravatar_for user, :size => 30 %> 3 | <%= link_to user.name, user %> 4 | <% if current_user.admin? %> 5 | | 6 | <%= link_to "delete", user, :method => :delete, :confirm => "You sure?", 7 | :title => "Delete #{user.name}" %> 8 | <% end %> 9 |
  • -------------------------------------------------------------------------------- /app/views/users/edit.html.erb: -------------------------------------------------------------------------------- 1 |

    Edit user

    2 | 3 | <%= form_for(@user) do |f| %> 4 | <%= render 'shared/error_messages', :object => f.object %> 5 | <%= render 'fields', :f => f %> 6 |
    7 | <%= f.submit "Update" %> 8 |
    9 | <% end %> 10 | 11 |
    12 | <%= gravatar_for @user %> 13 | change 14 |
    15 | -------------------------------------------------------------------------------- /app/views/users/index.html.erb: -------------------------------------------------------------------------------- 1 |

    All users

    2 | 3 | <%= will_paginate %> 4 | 5 | 8 | 9 | <%= will_paginate %> 10 | -------------------------------------------------------------------------------- /app/views/users/new.html.erb: -------------------------------------------------------------------------------- 1 |

    Sign up

    2 | 3 | <%= form_for(@user) do |f| %> 4 | <%= render 'shared/error_messages', :object => f.object %> 5 | <%= render 'fields', :f => f %> 6 |
    7 | <%= f.submit "Sign up" %> 8 |
    9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/users/show.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 22 | 23 |
    4 |

    5 | <%= gravatar_for @user %> 6 | <%= @user.name %> 7 |

    8 | <%= render 'follow_form' if signed_in? %> 9 | <% if @user.microposts.any? %> 10 | 11 | <%= render @microposts %> 12 |
    13 | <%= will_paginate @microposts %> 14 | <% end %> 15 |
    24 | 25 | -------------------------------------------------------------------------------- /app/views/users/show_follow.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 24 | 25 |
    4 |

    <%= @title %>

    5 | 6 | <% if @users.any? %> 7 |
      8 | <%= render @users %> 9 |
    10 | <%= will_paginate @users %> 11 | <% end %> 12 |
    -------------------------------------------------------------------------------- /autotest/discover.rb: -------------------------------------------------------------------------------- 1 | Autotest.add_discovery { "rails" } 2 | Autotest.add_discovery { "rspec2" } 3 | -------------------------------------------------------------------------------- /bin/annotate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'annotate' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('annotate', 'annotate') 17 | -------------------------------------------------------------------------------- /bin/autospec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'autospec' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rspec-core', 'autospec') 17 | -------------------------------------------------------------------------------- /bin/autotest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'autotest' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('ZenTest', 'autotest') 17 | -------------------------------------------------------------------------------- /bin/erubis: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'erubis' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('erubis', 'erubis') 17 | -------------------------------------------------------------------------------- /bin/htmldiff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'htmldiff' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('diff-lcs', 'htmldiff') 17 | -------------------------------------------------------------------------------- /bin/ldiff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'ldiff' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('diff-lcs', 'ldiff') 17 | -------------------------------------------------------------------------------- /bin/multigem: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'multigem' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('ZenTest', 'multigem') 17 | -------------------------------------------------------------------------------- /bin/multiruby: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'multiruby' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('ZenTest', 'multiruby') 17 | -------------------------------------------------------------------------------- /bin/multiruby_setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'multiruby_setup' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('ZenTest', 'multiruby_setup') 17 | -------------------------------------------------------------------------------- /bin/nokogiri: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'nokogiri' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('nokogiri', 'nokogiri') 17 | -------------------------------------------------------------------------------- /bin/rackup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rackup' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rack', 'rackup') 17 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rails' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rails', 'rails') 17 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rake' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rake', 'rake') 17 | -------------------------------------------------------------------------------- /bin/rake2thor: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rake2thor' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('thor', 'rake2thor') 17 | -------------------------------------------------------------------------------- /bin/rdoc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rdoc' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rdoc', 'rdoc') 17 | -------------------------------------------------------------------------------- /bin/ri: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'ri' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rdoc', 'ri') 17 | -------------------------------------------------------------------------------- /bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rspec' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rspec-core', 'rspec') 17 | -------------------------------------------------------------------------------- /bin/spork: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'spork' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('spork', 'spork') 17 | -------------------------------------------------------------------------------- /bin/thor: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'thor' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('thor', 'thor') 17 | -------------------------------------------------------------------------------- /bin/tt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'tt' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('treetop', 'tt') 17 | -------------------------------------------------------------------------------- /bin/unit_diff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'unit_diff' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('ZenTest', 'unit_diff') 17 | -------------------------------------------------------------------------------- /bin/zentest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'zentest' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('ZenTest', 'zentest') 17 | -------------------------------------------------------------------------------- /bundler_stubs/annotate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'annotate' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('annotate', 'annotate') 17 | -------------------------------------------------------------------------------- /bundler_stubs/autospec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'autospec' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rspec-core', 'autospec') 17 | -------------------------------------------------------------------------------- /bundler_stubs/erubis: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'erubis' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('erubis', 'erubis') 17 | -------------------------------------------------------------------------------- /bundler_stubs/htmldiff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'htmldiff' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('diff-lcs', 'htmldiff') 17 | -------------------------------------------------------------------------------- /bundler_stubs/ldiff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'ldiff' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('diff-lcs', 'ldiff') 17 | -------------------------------------------------------------------------------- /bundler_stubs/nokogiri: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'nokogiri' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('nokogiri', 'nokogiri') 17 | -------------------------------------------------------------------------------- /bundler_stubs/rackup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rackup' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rack', 'rackup') 17 | -------------------------------------------------------------------------------- /bundler_stubs/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rails' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rails', 'rails') 17 | -------------------------------------------------------------------------------- /bundler_stubs/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rake' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rake', 'rake') 17 | -------------------------------------------------------------------------------- /bundler_stubs/rake2thor: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rake2thor' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('thor', 'rake2thor') 17 | -------------------------------------------------------------------------------- /bundler_stubs/rdoc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rdoc' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rdoc', 'rdoc') 17 | -------------------------------------------------------------------------------- /bundler_stubs/ri: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'ri' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rdoc', 'ri') 17 | -------------------------------------------------------------------------------- /bundler_stubs/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'rspec' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('rspec-core', 'rspec') 17 | -------------------------------------------------------------------------------- /bundler_stubs/spork: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'spork' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('spork', 'spork') 17 | -------------------------------------------------------------------------------- /bundler_stubs/thor: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'thor' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('thor', 'thor') 17 | -------------------------------------------------------------------------------- /bundler_stubs/tt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'tt' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('treetop', 'tt') 17 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run SampleApp::Application 5 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 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 SampleApp 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 | # Custom directories with classes and modules you want to be autoloadable. 16 | # config.autoload_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 | # JavaScript files you want as :defaults (application.js is always included). 34 | # config.action_view.javascript_expansions[:defaults] = %w(jquery rails) 35 | 36 | # Configure the default encoding used in templates for Ruby 1.9. 37 | config.encoding = "utf-8" 38 | 39 | # Configure sensitive parameters which will be filtered from the log file. 40 | config.filter_parameters += [:password] 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | gemfile = File.expand_path('../../Gemfile', __FILE__) 5 | begin 6 | ENV['BUNDLE_GEMFILE'] = gemfile 7 | require 'bundler' 8 | Bundler.setup 9 | rescue Bundler::GemNotFound => e 10 | STDERR.puts e.message 11 | STDERR.puts "Try running `bundle install`." 12 | exit! 13 | end if File.exist?(gemfile) 14 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 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 23 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | SampleApp::Application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | SampleApp::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 | 20 | # Print deprecation notices to the Rails logger 21 | config.active_support.deprecation = :log 22 | end 23 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | SampleApp::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 | 43 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 44 | # the I18n.default_locale when a translation can not be found) 45 | config.i18n.fallbacks = true 46 | 47 | # Send deprecation notices to registered listeners 48 | config.active_support.deprecation = :notify 49 | end 50 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | SampleApp::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 | 33 | # Print deprecation notices to the stderr 34 | config.active_support.deprecation = :stderr 35 | end 36 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 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! 8 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 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 11 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 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 6 | -------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 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 | SampleApp::Application.config.secret_token = '30df044d52659429e4a8b0b0620397c49ff7acc241b9c8fc24aaad9f0292a3db3cd0ba77084213e74286ea4b9c5df3992cf16532c3e454a152e08889a8eb3d2e' 8 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | SampleApp::Application.config.session_store :cookie_store, :key => '_sample_app_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 | # SampleApp::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 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" 6 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | SampleApp::Application.routes.draw do 2 | 3 | resources :users do 4 | member do 5 | get :following, :followers 6 | end 7 | end 8 | 9 | resources :sessions, :only => [:new, :create, :destroy] 10 | resources :microposts, :only => [:create, :destroy] 11 | resources :relationships, :only => [:create, :destroy] 12 | 13 | root :to => "pages#home" 14 | 15 | match '/contact', :to => 'pages#contact' 16 | match '/about', :to => 'pages#about' 17 | match '/help', :to => 'pages#help' 18 | match '/signup', :to => 'users#new' 19 | match '/signin', :to => 'sessions#new' 20 | match '/signout', :to => 'sessions#destroy' 21 | 22 | # The priority is based upon order of creation: 23 | # first created -> highest priority. 24 | 25 | # Sample of regular route: 26 | # match 'products/:id' => 'catalog#view' 27 | # Keep in mind you can assign values other than :controller and :action 28 | 29 | # Sample of named route: 30 | # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase 31 | # This route can be invoked with purchase_url(:id => product.id) 32 | 33 | # Sample resource route (maps HTTP verbs to controller actions automatically): 34 | # resources :products 35 | 36 | # Sample resource route with options: 37 | # resources :products do 38 | # member do 39 | # get :short 40 | # post :toggle 41 | # end 42 | # 43 | # collection do 44 | # get :sold 45 | # end 46 | # end 47 | 48 | # Sample resource route with sub-resources: 49 | # resources :products do 50 | # resources :comments, :sales 51 | # resource :seller 52 | # end 53 | 54 | # Sample resource route with more complex sub-resources 55 | # resources :products do 56 | # resources :comments 57 | # resources :sales do 58 | # get :recent, :on => :collection 59 | # end 60 | # end 61 | 62 | # Sample resource route within a namespace: 63 | # namespace :admin do 64 | # # Directs /admin/products/* to Admin::ProductsController 65 | # # (app/controllers/admin/products_controller.rb) 66 | # resources :products 67 | # end 68 | 69 | # You can have the root of your site routed with "root" 70 | # just remember to delete public/index.html. 71 | # root :to => "welcome#index" 72 | 73 | # See how all your routes lay out with "rake routes" 74 | 75 | # This is a legacy wild controller route that's not recommended for RESTful applications. 76 | # Note: This route will make all actions in every controller accessible via GET requests. 77 | # match ':controller(/:action(/:id(.:format)))' 78 | end 79 | -------------------------------------------------------------------------------- /db/migrate/20100821203213_create_users.rb: -------------------------------------------------------------------------------- 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 15 | -------------------------------------------------------------------------------- /db/migrate/20100822012431_add_email_uniqueness_index.rb: -------------------------------------------------------------------------------- 1 | class AddEmailUniquenessIndex < ActiveRecord::Migration 2 | def self.up 3 | add_index :users, :email, :unique => true 4 | end 5 | 6 | def self.down 7 | remove_index :users, :email 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20100822204528_add_password_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddPasswordToUsers < ActiveRecord::Migration 2 | def self.up 3 | add_column :users, :encrypted_password, :string 4 | end 5 | 6 | def self.down 7 | remove_column :users, :encrypted_password 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20100822233125_add_salt_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddSaltToUsers < ActiveRecord::Migration 2 | def self.up 3 | add_column :users, :salt, :string 4 | end 5 | 6 | def self.down 7 | remove_column :users, :salt 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20100829021049_add_admin_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAdminToUsers < ActiveRecord::Migration 2 | def self.up 3 | add_column :users, :admin, :boolean, :default => false 4 | end 5 | 6 | def self.down 7 | remove_column :users, :admin 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20100829210229_create_microposts.rb: -------------------------------------------------------------------------------- 1 | class CreateMicroposts < ActiveRecord::Migration 2 | def self.up 3 | create_table :microposts do |t| 4 | t.string :content 5 | t.integer :user_id 6 | 7 | t.timestamps 8 | end 9 | add_index :microposts, [:user_id, :created_at] 10 | end 11 | 12 | def self.down 13 | drop_table :microposts 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20100831012055_create_relationships.rb: -------------------------------------------------------------------------------- 1 | class CreateRelationships < ActiveRecord::Migration 2 | def self.up 3 | create_table :relationships do |t| 4 | t.integer :follower_id 5 | t.integer :followed_id 6 | 7 | t.timestamps 8 | end 9 | add_index :relationships, :follower_id 10 | add_index :relationships, :followed_id 11 | add_index :relationships, [:follower_id, :followed_id], :unique => true 12 | end 13 | 14 | def self.down 15 | drop_table :relationships 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended to check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(:version => 20100831012055) do 15 | 16 | create_table "microposts", :force => true do |t| 17 | t.string "content" 18 | t.integer "user_id" 19 | t.datetime "created_at" 20 | t.datetime "updated_at" 21 | end 22 | 23 | add_index "microposts", ["user_id", "created_at"], :name => "index_microposts_on_user_id_and_created_at" 24 | 25 | create_table "relationships", :force => true do |t| 26 | t.integer "follower_id" 27 | t.integer "followed_id" 28 | t.datetime "created_at" 29 | t.datetime "updated_at" 30 | end 31 | 32 | add_index "relationships", ["followed_id"], :name => "index_relationships_on_followed_id" 33 | add_index "relationships", ["follower_id", "followed_id"], :name => "index_relationships_on_follower_id_and_followed_id", :unique => true 34 | add_index "relationships", ["follower_id"], :name => "index_relationships_on_follower_id" 35 | 36 | create_table "users", :force => true do |t| 37 | t.string "name" 38 | t.string "email" 39 | t.datetime "created_at" 40 | t.datetime "updated_at" 41 | t.string "encrypted_password" 42 | t.string "salt" 43 | t.boolean "admin", :default => false 44 | end 45 | 46 | add_index "users", ["email"], :name => "index_users_on_email", :unique => true 47 | 48 | end 49 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 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) 8 | -------------------------------------------------------------------------------- /doc/README_FOR_APP: -------------------------------------------------------------------------------- 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. 3 | -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /lib/tasks/sample_data.rake: -------------------------------------------------------------------------------- 1 | namespace :db do 2 | desc "Fill database with sample data" 3 | task :populate => :environment do 4 | Rake::Task['db:reset'].invoke 5 | make_users 6 | make_microposts 7 | make_relationships 8 | end 9 | end 10 | 11 | def make_users 12 | admin = User.create!(:name => "Example User", 13 | :email => "example@railstutorial.org", 14 | :password => "foobar", 15 | :password_confirmation => "foobar") 16 | admin.toggle!(:admin) 17 | 99.times do |n| 18 | name = Faker::Name.name 19 | email = "example-#{n+1}@railstutorial.org" 20 | password = "password" 21 | User.create!(:name => name, 22 | :email => email, 23 | :password => password, 24 | :password_confirmation => password) 25 | end 26 | end 27 | 28 | def make_microposts 29 | 50.times do 30 | User.all(:limit => 6).each do |user| 31 | user.microposts.create!(:content => Faker::Lorem.sentence(5)) 32 | end 33 | end 34 | end 35 | 36 | def make_relationships 37 | users = User.all 38 | user = users.first 39 | following = users[1..50] 40 | followers = users[3..40] 41 | following.each { |followed| user.follow!(followed) } 42 | followers.each { |follower| follower.follow!(user) } 43 | end -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
    22 |

    The page you were looking for doesn't exist.

    23 |

    You may have mistyped the address or the page may have moved.

    24 |
    25 | 26 | 27 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
    22 |

    The change you wanted was rejected.

    23 |

    Maybe you tried to change something you didn't have access to.

    24 |
    25 | 26 | 27 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
    22 |

    We're sorry, but something went wrong.

    23 |

    We've been notified about this issue and we'll take a look at it shortly.

    24 |
    25 | 26 | 27 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/favicon.ico -------------------------------------------------------------------------------- /public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/images/logo.png -------------------------------------------------------------------------------- /public/images/rails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/images/rails.png -------------------------------------------------------------------------------- /public/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // Place your application-specific JavaScript functions and classes here 2 | // This file is automatically included by javascript_include_tag :defaults 3 | -------------------------------------------------------------------------------- /public/javascripts/rails.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | // Technique from Juriy Zaytsev 3 | // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ 4 | function isEventSupported(eventName) { 5 | var el = document.createElement('div'); 6 | eventName = 'on' + eventName; 7 | var isSupported = (eventName in el); 8 | if (!isSupported) { 9 | el.setAttribute(eventName, 'return;'); 10 | isSupported = typeof el[eventName] == 'function'; 11 | } 12 | el = null; 13 | return isSupported; 14 | } 15 | 16 | function isForm(element) { 17 | return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM' 18 | } 19 | 20 | function isInput(element) { 21 | if (Object.isElement(element)) { 22 | var name = element.nodeName.toUpperCase() 23 | return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA' 24 | } 25 | else return false 26 | } 27 | 28 | var submitBubbles = isEventSupported('submit'), 29 | changeBubbles = isEventSupported('change') 30 | 31 | if (!submitBubbles || !changeBubbles) { 32 | // augment the Event.Handler class to observe custom events when needed 33 | Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap( 34 | function(init, element, eventName, selector, callback) { 35 | init(element, eventName, selector, callback) 36 | // is the handler being attached to an element that doesn't support this event? 37 | if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) || 38 | (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) { 39 | // "submit" => "emulated:submit" 40 | this.eventName = 'emulated:' + this.eventName 41 | } 42 | } 43 | ) 44 | } 45 | 46 | if (!submitBubbles) { 47 | // discover forms on the page by observing focus events which always bubble 48 | document.on('focusin', 'form', function(focusEvent, form) { 49 | // special handler for the real "submit" event (one-time operation) 50 | if (!form.retrieve('emulated:submit')) { 51 | form.on('submit', function(submitEvent) { 52 | var emulated = form.fire('emulated:submit', submitEvent, true) 53 | // if custom event received preventDefault, cancel the real one too 54 | if (emulated.returnValue === false) submitEvent.preventDefault() 55 | }) 56 | form.store('emulated:submit', true) 57 | } 58 | }) 59 | } 60 | 61 | if (!changeBubbles) { 62 | // discover form inputs on the page 63 | document.on('focusin', 'input, select, texarea', function(focusEvent, input) { 64 | // special handler for real "change" events 65 | if (!input.retrieve('emulated:change')) { 66 | input.on('change', function(changeEvent) { 67 | input.fire('emulated:change', changeEvent, true) 68 | }) 69 | input.store('emulated:change', true) 70 | } 71 | }) 72 | } 73 | 74 | function handleRemote(element) { 75 | var method, url, params; 76 | 77 | var event = element.fire("ajax:before"); 78 | if (event.stopped) return false; 79 | 80 | if (element.tagName.toLowerCase() === 'form') { 81 | method = element.readAttribute('method') || 'post'; 82 | url = element.readAttribute('action'); 83 | params = element.serialize(); 84 | } else { 85 | method = element.readAttribute('data-method') || 'get'; 86 | url = element.readAttribute('href'); 87 | params = {}; 88 | } 89 | 90 | new Ajax.Request(url, { 91 | method: method, 92 | parameters: params, 93 | evalScripts: true, 94 | 95 | onComplete: function(request) { element.fire("ajax:complete", request); }, 96 | onSuccess: function(request) { element.fire("ajax:success", request); }, 97 | onFailure: function(request) { element.fire("ajax:failure", request); } 98 | }); 99 | 100 | element.fire("ajax:after"); 101 | } 102 | 103 | function handleMethod(element) { 104 | var method = element.readAttribute('data-method'), 105 | url = element.readAttribute('href'), 106 | csrf_param = $$('meta[name=csrf-param]')[0], 107 | csrf_token = $$('meta[name=csrf-token]')[0]; 108 | 109 | var form = new Element('form', { method: "POST", action: url, style: "display: none;" }); 110 | element.parentNode.insert(form); 111 | 112 | if (method !== 'post') { 113 | var field = new Element('input', { type: 'hidden', name: '_method', value: method }); 114 | form.insert(field); 115 | } 116 | 117 | if (csrf_param) { 118 | var param = csrf_param.readAttribute('content'), 119 | token = csrf_token.readAttribute('content'), 120 | field = new Element('input', { type: 'hidden', name: param, value: token }); 121 | form.insert(field); 122 | } 123 | 124 | form.submit(); 125 | } 126 | 127 | 128 | document.on("click", "*[data-confirm]", function(event, element) { 129 | var message = element.readAttribute('data-confirm'); 130 | if (!confirm(message)) event.stop(); 131 | }); 132 | 133 | document.on("click", "a[data-remote]", function(event, element) { 134 | if (event.stopped) return; 135 | handleRemote(element); 136 | event.stop(); 137 | }); 138 | 139 | document.on("click", "a[data-method]", function(event, element) { 140 | if (event.stopped) return; 141 | handleMethod(element); 142 | event.stop(); 143 | }); 144 | 145 | document.on("submit", function(event) { 146 | var element = event.findElement(), 147 | message = element.readAttribute('data-confirm'); 148 | if (message && !confirm(message)) { 149 | event.stop(); 150 | return false; 151 | } 152 | 153 | var inputs = element.select("input[type=submit][data-disable-with]"); 154 | inputs.each(function(input) { 155 | input.disabled = true; 156 | input.writeAttribute('data-original-value', input.value); 157 | input.value = input.readAttribute('data-disable-with'); 158 | }); 159 | 160 | var element = event.findElement("form[data-remote]"); 161 | if (element) { 162 | handleRemote(element); 163 | event.stop(); 164 | } 165 | }); 166 | 167 | document.on("ajax:after", "form", function(event, element) { 168 | var inputs = element.select("input[type=submit][disabled=true][data-disable-with]"); 169 | inputs.each(function(input) { 170 | input.value = input.readAttribute('data-original-value'); 171 | input.removeAttribute('data-original-value'); 172 | input.disabled = false; 173 | }); 174 | }); 175 | })(); 176 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-Agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /public/stylesheets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/.gitkeep -------------------------------------------------------------------------------- /public/stylesheets/blueprint/ie.css: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | 3 | 4 | Blueprint CSS Framework 0.9 5 | http://blueprintcss.org 6 | 7 | * Copyright (c) 2007-Present. See LICENSE for more info. 8 | * See README for instructions on how to use Blueprint. 9 | * For credits and origins, see AUTHORS. 10 | * This is a compressed file. See the sources in the 'src' directory. 11 | 12 | ----------------------------------------------------------------------- */ 13 | 14 | /* ie.css */ 15 | body {text-align:center;} 16 | .container {text-align:left;} 17 | * html .column, * html .span-1, * html .span-2, * html .span-3, * html .span-4, * html .span-5, * html .span-6, * html .span-7, * html .span-8, * html .span-9, * html .span-10, * html .span-11, * html .span-12, * html .span-13, * html .span-14, * html .span-15, * html .span-16, * html .span-17, * html .span-18, * html .span-19, * html .span-20, * html .span-21, * html .span-22, * html .span-23, * html .span-24 {display:inline;overflow-x:hidden;} 18 | * html legend {margin:0px -8px 16px 0;padding:0;} 19 | sup {vertical-align:text-top;} 20 | sub {vertical-align:text-bottom;} 21 | html>body p code {*white-space:normal;} 22 | hr {margin:-8px auto 11px;} 23 | img {-ms-interpolation-mode:bicubic;} 24 | .clearfix, .container {display:inline-block;} 25 | * html .clearfix, * html .container {height:1%;} 26 | fieldset {padding-top:0;} 27 | textarea {overflow:auto;} 28 | input.text, input.title, textarea {background-color:#fff;border:1px solid #bbb;} 29 | input.text:focus, input.title:focus {border-color:#666;} 30 | input.text, input.title, textarea, select {margin:0.5em 0;} 31 | input.checkbox, input.radio {position:relative;top:.25em;} 32 | form.inline div, form.inline p {vertical-align:middle;} 33 | form.inline label {position:relative;top:-0.25em;} 34 | form.inline input.checkbox, form.inline input.radio, form.inline input.button, form.inline button {margin:0.5em 0;} 35 | button, input.button {position:relative;top:0.25em;} -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/buttons/icons/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/plugins/buttons/icons/cross.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/buttons/icons/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/plugins/buttons/icons/key.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/buttons/icons/tick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/plugins/buttons/icons/tick.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/buttons/readme.txt: -------------------------------------------------------------------------------- 1 | Buttons 2 | 3 | * Gives you great looking CSS buttons, for both and 25 | 26 | 27 | Change Password 28 | 29 | 30 | 31 | Cancel 32 | 33 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/buttons/screen.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | buttons.css 4 | * Gives you some great CSS-only buttons. 5 | 6 | Created by Kevin Hale [particletree.com] 7 | * particletree.com/features/rediscovering-the-button-element 8 | 9 | See Readme.txt in this folder for instructions. 10 | 11 | -------------------------------------------------------------- */ 12 | 13 | a.button, button { 14 | display:block; 15 | float:left; 16 | margin: 0.7em 0.5em 0.7em 0; 17 | padding:5px 10px 5px 7px; /* Links */ 18 | 19 | border:1px solid #dedede; 20 | border-top:1px solid #eee; 21 | border-left:1px solid #eee; 22 | 23 | background-color:#f5f5f5; 24 | font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif; 25 | font-size:100%; 26 | line-height:130%; 27 | text-decoration:none; 28 | font-weight:bold; 29 | color:#565656; 30 | cursor:pointer; 31 | } 32 | button { 33 | width:auto; 34 | overflow:visible; 35 | padding:4px 10px 3px 7px; /* IE6 */ 36 | } 37 | button[type] { 38 | padding:4px 10px 4px 7px; /* Firefox */ 39 | line-height:17px; /* Safari */ 40 | } 41 | *:first-child+html button[type] { 42 | padding:4px 10px 3px 7px; /* IE7 */ 43 | } 44 | button img, a.button img{ 45 | margin:0 3px -3px 0 !important; 46 | padding:0; 47 | border:none; 48 | width:16px; 49 | height:16px; 50 | float:none; 51 | } 52 | 53 | 54 | /* Button colors 55 | -------------------------------------------------------------- */ 56 | 57 | /* Standard */ 58 | button:hover, a.button:hover{ 59 | background-color:#dff4ff; 60 | border:1px solid #c2e1ef; 61 | color:#336699; 62 | } 63 | a.button:active{ 64 | background-color:#6299c5; 65 | border:1px solid #6299c5; 66 | color:#fff; 67 | } 68 | 69 | /* Positive */ 70 | body .positive { 71 | color:#529214; 72 | } 73 | a.positive:hover, button.positive:hover { 74 | background-color:#E6EFC2; 75 | border:1px solid #C6D880; 76 | color:#529214; 77 | } 78 | a.positive:active { 79 | background-color:#529214; 80 | border:1px solid #529214; 81 | color:#fff; 82 | } 83 | 84 | /* Negative */ 85 | body .negative { 86 | color:#d12f19; 87 | } 88 | a.negative:hover, button.negative:hover { 89 | background-color:#fbe3e4; 90 | border:1px solid #fbc2c4; 91 | color:#d12f19; 92 | } 93 | a.negative:active { 94 | background-color:#d12f19; 95 | border:1px solid #d12f19; 96 | color:#fff; 97 | } 98 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/fancy-type/readme.txt: -------------------------------------------------------------------------------- 1 | Fancy Type 2 | 3 | * Gives you classes to use if you'd like some 4 | extra fancy typography. 5 | 6 | Credits and instructions are specified above each class 7 | in the fancy-type.css file in this directory. 8 | 9 | 10 | Usage 11 | ---------------------------------------------------------------- 12 | 13 | 1) Add this plugin to lib/settings.yml. 14 | See compress.rb for instructions. 15 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/fancy-type/screen.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | fancy-type.css 4 | * Lots of pretty advanced classes for manipulating text. 5 | 6 | See the Readme file in this folder for additional instructions. 7 | 8 | -------------------------------------------------------------- */ 9 | 10 | /* Indentation instead of line shifts for sibling paragraphs. */ 11 | p + p { text-indent:2em; margin-top:-1.5em; } 12 | form p + p { text-indent: 0; } /* Don't want this in forms. */ 13 | 14 | 15 | /* For great looking type, use this code instead of asdf: 16 | asdf 17 | Best used on prepositions and ampersands. */ 18 | 19 | .alt { 20 | color: #666; 21 | font-family: "Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua", Georgia, serif; 22 | font-style: italic; 23 | font-weight: normal; 24 | } 25 | 26 | 27 | /* For great looking quote marks in titles, replace "asdf" with: 28 | asdf” 29 | (That is, when the title starts with a quote mark). 30 | (You may have to change this value depending on your font size). */ 31 | 32 | .dquo { margin-left: -.5em; } 33 | 34 | 35 | /* Reduced size type with incremental leading 36 | (http://www.markboulton.co.uk/journal/comments/incremental_leading/) 37 | 38 | This could be used for side notes. For smaller type, you don't necessarily want to 39 | follow the 1.5x vertical rhythm -- the line-height is too much. 40 | 41 | Using this class, it reduces your font size and line-height so that for 42 | every four lines of normal sized type, there is five lines of the sidenote. eg: 43 | 44 | New type size in em's: 45 | 10px (wanted side note size) / 12px (existing base size) = 0.8333 (new type size in ems) 46 | 47 | New line-height value: 48 | 12px x 1.5 = 18px (old line-height) 49 | 18px x 4 = 72px 50 | 72px / 5 = 14.4px (new line height) 51 | 14.4px / 10px = 1.44 (new line height in em's) */ 52 | 53 | p.incr, .incr p { 54 | font-size: 10px; 55 | line-height: 1.44em; 56 | margin-bottom: 1.5em; 57 | } 58 | 59 | 60 | /* Surround uppercase words and abbreviations with this class. 61 | Based on work by Jørgen Arnor Gårdsø Lom [http://twistedintellect.com/] */ 62 | 63 | .caps { 64 | font-variant: small-caps; 65 | letter-spacing: 1px; 66 | text-transform: lowercase; 67 | font-size:1.2em; 68 | line-height:1%; 69 | font-weight:bold; 70 | padding:0 2px; 71 | } 72 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/link-icons/icons/doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/plugins/link-icons/icons/doc.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/link-icons/icons/email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/plugins/link-icons/icons/email.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/link-icons/icons/external.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/plugins/link-icons/icons/external.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/link-icons/icons/feed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/plugins/link-icons/icons/feed.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/link-icons/icons/im.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/plugins/link-icons/icons/im.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/link-icons/icons/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/plugins/link-icons/icons/pdf.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/link-icons/icons/visited.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/plugins/link-icons/icons/visited.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/link-icons/icons/xls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/plugins/link-icons/icons/xls.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/link-icons/readme.txt: -------------------------------------------------------------------------------- 1 | Link Icons 2 | * Icons for links based on protocol or file type. 3 | 4 | This is not supported in IE versions < 7. 5 | 6 | 7 | Credits 8 | ---------------------------------------------------------------- 9 | 10 | * Marc Morgan 11 | * Olav Bjorkoy [bjorkoy.com] 12 | 13 | 14 | Usage 15 | ---------------------------------------------------------------- 16 | 17 | 1) Add this line to your HTML: 18 | 19 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/link-icons/screen.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | link-icons.css 4 | * Icons for links based on protocol or file type. 5 | 6 | See the Readme file in this folder for additional instructions. 7 | 8 | -------------------------------------------------------------- */ 9 | 10 | /* Use this class if a link gets an icon when it shouldn't. */ 11 | body a.noicon { 12 | background:transparent none !important; 13 | padding:0 !important; 14 | margin:0 !important; 15 | } 16 | 17 | /* Make sure the icons are not cut */ 18 | a[href^="http:"], a[href^="mailto:"], a[href^="http:"]:visited, 19 | a[href$=".pdf"], a[href$=".doc"], a[href$=".xls"], a[href$=".rss"], 20 | a[href$=".rdf"], a[href^="aim:"] { 21 | padding:2px 22px 2px 0; 22 | margin:-2px 0; 23 | background-repeat: no-repeat; 24 | background-position: right center; 25 | } 26 | 27 | /* External links */ 28 | a[href^="http:"] { background-image: url(icons/external.png); } 29 | a[href^="mailto:"] { background-image: url(icons/email.png); } 30 | a[href^="http:"]:visited { background-image: url(icons/visited.png); } 31 | 32 | /* Files */ 33 | a[href$=".pdf"] { background-image: url(icons/pdf.png); } 34 | a[href$=".doc"] { background-image: url(icons/doc.png); } 35 | a[href$=".xls"] { background-image: url(icons/xls.png); } 36 | 37 | /* Misc */ 38 | a[href$=".rss"], 39 | a[href$=".rdf"] { background-image: url(icons/feed.png); } 40 | a[href^="aim:"] { background-image: url(icons/im.png); } 41 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/rtl/readme.txt: -------------------------------------------------------------------------------- 1 | RTL 2 | * Mirrors Blueprint, so it can be used with Right-to-Left languages. 3 | 4 | By Ran Yaniv Hartstein, ranh.co.il 5 | 6 | Usage 7 | ---------------------------------------------------------------- 8 | 9 | 1) Add this line to your HTML: 10 | 11 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/plugins/rtl/screen.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | rtl.css 4 | * Mirrors Blueprint for left-to-right languages 5 | 6 | By Ran Yaniv Hartstein [ranh.co.il] 7 | 8 | -------------------------------------------------------------- */ 9 | 10 | body .container { direction: rtl; } 11 | body .column, body .span-1, body .span-2, body .span-3, body .span-4, body .span-5, body .span-6, body .span-7, body .span-8, body .span-9, body .span-10, body .span-11, body .span-12, body .span-13, body .span-14, body .span-15, body .span-16, body .span-17, body .span-18, body .span-19, body .span-20, body .span-21, body .span-22, body .span-23, body .span-24 { 12 | float: right; 13 | margin-right: 0; 14 | margin-left: 10px; 15 | text-align:right; 16 | } 17 | 18 | body div.last { margin-left: 0; } 19 | body table .last { padding-left: 0; } 20 | 21 | body .append-1 { padding-right: 0; padding-left: 40px; } 22 | body .append-2 { padding-right: 0; padding-left: 80px; } 23 | body .append-3 { padding-right: 0; padding-left: 120px; } 24 | body .append-4 { padding-right: 0; padding-left: 160px; } 25 | body .append-5 { padding-right: 0; padding-left: 200px; } 26 | body .append-6 { padding-right: 0; padding-left: 240px; } 27 | body .append-7 { padding-right: 0; padding-left: 280px; } 28 | body .append-8 { padding-right: 0; padding-left: 320px; } 29 | body .append-9 { padding-right: 0; padding-left: 360px; } 30 | body .append-10 { padding-right: 0; padding-left: 400px; } 31 | body .append-11 { padding-right: 0; padding-left: 440px; } 32 | body .append-12 { padding-right: 0; padding-left: 480px; } 33 | body .append-13 { padding-right: 0; padding-left: 520px; } 34 | body .append-14 { padding-right: 0; padding-left: 560px; } 35 | body .append-15 { padding-right: 0; padding-left: 600px; } 36 | body .append-16 { padding-right: 0; padding-left: 640px; } 37 | body .append-17 { padding-right: 0; padding-left: 680px; } 38 | body .append-18 { padding-right: 0; padding-left: 720px; } 39 | body .append-19 { padding-right: 0; padding-left: 760px; } 40 | body .append-20 { padding-right: 0; padding-left: 800px; } 41 | body .append-21 { padding-right: 0; padding-left: 840px; } 42 | body .append-22 { padding-right: 0; padding-left: 880px; } 43 | body .append-23 { padding-right: 0; padding-left: 920px; } 44 | 45 | body .prepend-1 { padding-left: 0; padding-right: 40px; } 46 | body .prepend-2 { padding-left: 0; padding-right: 80px; } 47 | body .prepend-3 { padding-left: 0; padding-right: 120px; } 48 | body .prepend-4 { padding-left: 0; padding-right: 160px; } 49 | body .prepend-5 { padding-left: 0; padding-right: 200px; } 50 | body .prepend-6 { padding-left: 0; padding-right: 240px; } 51 | body .prepend-7 { padding-left: 0; padding-right: 280px; } 52 | body .prepend-8 { padding-left: 0; padding-right: 320px; } 53 | body .prepend-9 { padding-left: 0; padding-right: 360px; } 54 | body .prepend-10 { padding-left: 0; padding-right: 400px; } 55 | body .prepend-11 { padding-left: 0; padding-right: 440px; } 56 | body .prepend-12 { padding-left: 0; padding-right: 480px; } 57 | body .prepend-13 { padding-left: 0; padding-right: 520px; } 58 | body .prepend-14 { padding-left: 0; padding-right: 560px; } 59 | body .prepend-15 { padding-left: 0; padding-right: 600px; } 60 | body .prepend-16 { padding-left: 0; padding-right: 640px; } 61 | body .prepend-17 { padding-left: 0; padding-right: 680px; } 62 | body .prepend-18 { padding-left: 0; padding-right: 720px; } 63 | body .prepend-19 { padding-left: 0; padding-right: 760px; } 64 | body .prepend-20 { padding-left: 0; padding-right: 800px; } 65 | body .prepend-21 { padding-left: 0; padding-right: 840px; } 66 | body .prepend-22 { padding-left: 0; padding-right: 880px; } 67 | body .prepend-23 { padding-left: 0; padding-right: 920px; } 68 | 69 | body .border { 70 | padding-right: 0; 71 | padding-left: 4px; 72 | margin-right: 0; 73 | margin-left: 5px; 74 | border-right: none; 75 | border-left: 1px solid #eee; 76 | } 77 | 78 | body .colborder { 79 | padding-right: 0; 80 | padding-left: 24px; 81 | margin-right: 0; 82 | margin-left: 25px; 83 | border-right: none; 84 | border-left: 1px solid #eee; 85 | } 86 | 87 | body .pull-1 { margin-left: 0; margin-right: -40px; } 88 | body .pull-2 { margin-left: 0; margin-right: -80px; } 89 | body .pull-3 { margin-left: 0; margin-right: -120px; } 90 | body .pull-4 { margin-left: 0; margin-right: -160px; } 91 | 92 | body .push-0 { margin: 0 18px 0 0; } 93 | body .push-1 { margin: 0 18px 0 -40px; } 94 | body .push-2 { margin: 0 18px 0 -80px; } 95 | body .push-3 { margin: 0 18px 0 -120px; } 96 | body .push-4 { margin: 0 18px 0 -160px; } 97 | body .push-0, body .push-1, body .push-2, 98 | body .push-3, body .push-4 { float: left; } 99 | 100 | 101 | /* Typography with RTL support */ 102 | body h1,body h2,body h3, 103 | body h4,body h5,body h6 { font-family: Arial, sans-serif; } 104 | html body { font-family: Arial, sans-serif; } 105 | body pre,body code,body tt { font-family: monospace; } 106 | 107 | /* Mirror floats and margins on typographic elements */ 108 | body p img { float: right; margin: 1.5em 0 1.5em 1.5em; } 109 | body dd, body ul, body ol { margin-left: 0; margin-right: 1.5em;} 110 | body td, body th { text-align:right; } 111 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/print.css: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | 3 | 4 | Blueprint CSS Framework 0.9 5 | http://blueprintcss.org 6 | 7 | * Copyright (c) 2007-Present. See LICENSE for more info. 8 | * See README for instructions on how to use Blueprint. 9 | * For credits and origins, see AUTHORS. 10 | * This is a compressed file. See the sources in the 'src' directory. 11 | 12 | ----------------------------------------------------------------------- */ 13 | 14 | /* print.css */ 15 | body {line-height:1.5;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;color:#000;background:none;font-size:10pt;} 16 | .container {background:none;} 17 | hr {background:#ccc;color:#ccc;width:100%;height:2px;margin:2em 0;padding:0;border:none;} 18 | hr.space {background:#fff;color:#fff;visibility:hidden;} 19 | h1, h2, h3, h4, h5, h6 {font-family:"Helvetica Neue", Arial, "Lucida Grande", sans-serif;} 20 | code {font:.9em "Courier New", Monaco, Courier, monospace;} 21 | a img {border:none;} 22 | p img.top {margin-top:0;} 23 | blockquote {margin:1.5em;padding:1em;font-style:italic;font-size:.9em;} 24 | .small {font-size:.9em;} 25 | .large {font-size:1.1em;} 26 | .quiet {color:#999;} 27 | .hide {display:none;} 28 | a:link, a:visited {background:transparent;font-weight:700;text-decoration:underline;} 29 | a:link:after, a:visited:after {content:" (" attr(href) ")";font-size:90%;} -------------------------------------------------------------------------------- /public/stylesheets/blueprint/screen.css: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | 3 | 4 | Blueprint CSS Framework 0.9 5 | http://blueprintcss.org 6 | 7 | * Copyright (c) 2007-Present. See LICENSE for more info. 8 | * See README for instructions on how to use Blueprint. 9 | * For credits and origins, see AUTHORS. 10 | * This is a compressed file. See the sources in the 'src' directory. 11 | 12 | ----------------------------------------------------------------------- */ 13 | 14 | /* reset.css */ 15 | html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, dialog, figure, footer, header, hgroup, nav, section {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;} 16 | article, aside, dialog, figure, footer, header, hgroup, nav, section {display:block;} 17 | body {line-height:1.5;} 18 | table {border-collapse:separate;border-spacing:0;} 19 | caption, th, td {text-align:left;font-weight:normal;} 20 | table, td, th {vertical-align:middle;} 21 | blockquote:before, blockquote:after, q:before, q:after {content:"";} 22 | blockquote, q {quotes:"" "";} 23 | a img {border:none;} 24 | 25 | /* typography.css */ 26 | html {font-size:100.01%;} 27 | body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;} 28 | h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;} 29 | h1 {font-size:3em;line-height:1;margin-bottom:0.5em;} 30 | h2 {font-size:2em;margin-bottom:0.75em;} 31 | h3 {font-size:1.5em;line-height:1;margin-bottom:1em;} 32 | h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;} 33 | h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;} 34 | h6 {font-size:1em;font-weight:bold;} 35 | h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;} 36 | p {margin:0 0 1.5em;} 37 | p img.left {float:left;margin:1.5em 1.5em 1.5em 0;padding:0;} 38 | p img.right {float:right;margin:1.5em 0 1.5em 1.5em;} 39 | a:focus, a:hover {color:#000;} 40 | a {color:#009;text-decoration:underline;} 41 | blockquote {margin:1.5em;color:#666;font-style:italic;} 42 | strong {font-weight:bold;} 43 | em, dfn {font-style:italic;} 44 | dfn {font-weight:bold;} 45 | sup, sub {line-height:0;} 46 | abbr, acronym {border-bottom:1px dotted #666;} 47 | address {margin:0 0 1.5em;font-style:italic;} 48 | del {color:#666;} 49 | pre {margin:1.5em 0;white-space:pre;} 50 | pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;} 51 | li ul, li ol {margin:0;} 52 | ul, ol {margin:0 1.5em 1.5em 0;padding-left:3.333em;} 53 | ul {list-style-type:disc;} 54 | ol {list-style-type:decimal;} 55 | dl {margin:0 0 1.5em 0;} 56 | dl dt {font-weight:bold;} 57 | dd {margin-left:1.5em;} 58 | table {margin-bottom:1.4em;width:100%;} 59 | th {font-weight:bold;} 60 | thead th {background:#c3d9ff;} 61 | th, td, caption {padding:4px 10px 4px 5px;} 62 | tr.even td {background:#e5ecf9;} 63 | tfoot {font-style:italic;} 64 | caption {background:#eee;} 65 | .small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;} 66 | .large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;} 67 | .hide {display:none;} 68 | .quiet {color:#666;} 69 | .loud {color:#000;} 70 | .highlight {background:#ff0;} 71 | .added {background:#060;color:#fff;} 72 | .removed {background:#900;color:#fff;} 73 | .first {margin-left:0;padding-left:0;} 74 | .last {margin-right:0;padding-right:0;} 75 | .top {margin-top:0;padding-top:0;} 76 | .bottom {margin-bottom:0;padding-bottom:0;} 77 | 78 | /* forms.css */ 79 | label {font-weight:bold;} 80 | fieldset {padding:1.4em;margin:0 0 1.5em 0;border:1px solid #ccc;} 81 | legend {font-weight:bold;font-size:1.2em;} 82 | input[type=text], input[type=password], input.text, input.title, textarea, select {background-color:#fff;border:1px solid #bbb;} 83 | input[type=text]:focus, input[type=password]:focus, input.text:focus, input.title:focus, textarea:focus, select:focus {border-color:#666;} 84 | input[type=text], input[type=password], input.text, input.title, textarea, select {margin:0.5em 0;} 85 | input.text, input.title {width:300px;padding:5px;} 86 | input.title {font-size:1.5em;} 87 | textarea {width:390px;height:250px;padding:5px;} 88 | input[type=checkbox], input[type=radio], input.checkbox, input.radio {position:relative;top:.25em;} 89 | form.inline {line-height:3;} 90 | form.inline p {margin-bottom:0;} 91 | .error, .notice, .success {padding:.8em;margin-bottom:1em;border:2px solid #ddd;} 92 | .error {background:#FBE3E4;color:#8a1f11;border-color:#FBC2C4;} 93 | .notice {background:#FFF6BF;color:#514721;border-color:#FFD324;} 94 | .success {background:#E6EFC2;color:#264409;border-color:#C6D880;} 95 | .error a {color:#8a1f11;} 96 | .notice a {color:#514721;} 97 | .success a {color:#264409;} 98 | 99 | /* grid.css */ 100 | .container {width:950px;margin:0 auto;} 101 | .showgrid {background:url(src/grid.png);} 102 | .column, .span-1, .span-2, .span-3, .span-4, .span-5, .span-6, .span-7, .span-8, .span-9, .span-10, .span-11, .span-12, .span-13, .span-14, .span-15, .span-16, .span-17, .span-18, .span-19, .span-20, .span-21, .span-22, .span-23, .span-24 {float:left;margin-right:10px;} 103 | .last {margin-right:0;} 104 | .span-1 {width:30px;} 105 | .span-2 {width:70px;} 106 | .span-3 {width:110px;} 107 | .span-4 {width:150px;} 108 | .span-5 {width:190px;} 109 | .span-6 {width:230px;} 110 | .span-7 {width:270px;} 111 | .span-8 {width:310px;} 112 | .span-9 {width:350px;} 113 | .span-10 {width:390px;} 114 | .span-11 {width:430px;} 115 | .span-12 {width:470px;} 116 | .span-13 {width:510px;} 117 | .span-14 {width:550px;} 118 | .span-15 {width:590px;} 119 | .span-16 {width:630px;} 120 | .span-17 {width:670px;} 121 | .span-18 {width:710px;} 122 | .span-19 {width:750px;} 123 | .span-20 {width:790px;} 124 | .span-21 {width:830px;} 125 | .span-22 {width:870px;} 126 | .span-23 {width:910px;} 127 | .span-24 {width:950px;margin-right:0;} 128 | input.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 {border-left-width:1px;border-right-width:1px;padding-left:5px;padding-right:5px;} 129 | input.span-1, textarea.span-1 {width:18px;} 130 | input.span-2, textarea.span-2 {width:58px;} 131 | input.span-3, textarea.span-3 {width:98px;} 132 | input.span-4, textarea.span-4 {width:138px;} 133 | input.span-5, textarea.span-5 {width:178px;} 134 | input.span-6, textarea.span-6 {width:218px;} 135 | input.span-7, textarea.span-7 {width:258px;} 136 | input.span-8, textarea.span-8 {width:298px;} 137 | input.span-9, textarea.span-9 {width:338px;} 138 | input.span-10, textarea.span-10 {width:378px;} 139 | input.span-11, textarea.span-11 {width:418px;} 140 | input.span-12, textarea.span-12 {width:458px;} 141 | input.span-13, textarea.span-13 {width:498px;} 142 | input.span-14, textarea.span-14 {width:538px;} 143 | input.span-15, textarea.span-15 {width:578px;} 144 | input.span-16, textarea.span-16 {width:618px;} 145 | input.span-17, textarea.span-17 {width:658px;} 146 | input.span-18, textarea.span-18 {width:698px;} 147 | input.span-19, textarea.span-19 {width:738px;} 148 | input.span-20, textarea.span-20 {width:778px;} 149 | input.span-21, textarea.span-21 {width:818px;} 150 | input.span-22, textarea.span-22 {width:858px;} 151 | input.span-23, textarea.span-23 {width:898px;} 152 | input.span-24, textarea.span-24 {width:938px;} 153 | .append-1 {padding-right:40px;} 154 | .append-2 {padding-right:80px;} 155 | .append-3 {padding-right:120px;} 156 | .append-4 {padding-right:160px;} 157 | .append-5 {padding-right:200px;} 158 | .append-6 {padding-right:240px;} 159 | .append-7 {padding-right:280px;} 160 | .append-8 {padding-right:320px;} 161 | .append-9 {padding-right:360px;} 162 | .append-10 {padding-right:400px;} 163 | .append-11 {padding-right:440px;} 164 | .append-12 {padding-right:480px;} 165 | .append-13 {padding-right:520px;} 166 | .append-14 {padding-right:560px;} 167 | .append-15 {padding-right:600px;} 168 | .append-16 {padding-right:640px;} 169 | .append-17 {padding-right:680px;} 170 | .append-18 {padding-right:720px;} 171 | .append-19 {padding-right:760px;} 172 | .append-20 {padding-right:800px;} 173 | .append-21 {padding-right:840px;} 174 | .append-22 {padding-right:880px;} 175 | .append-23 {padding-right:920px;} 176 | .prepend-1 {padding-left:40px;} 177 | .prepend-2 {padding-left:80px;} 178 | .prepend-3 {padding-left:120px;} 179 | .prepend-4 {padding-left:160px;} 180 | .prepend-5 {padding-left:200px;} 181 | .prepend-6 {padding-left:240px;} 182 | .prepend-7 {padding-left:280px;} 183 | .prepend-8 {padding-left:320px;} 184 | .prepend-9 {padding-left:360px;} 185 | .prepend-10 {padding-left:400px;} 186 | .prepend-11 {padding-left:440px;} 187 | .prepend-12 {padding-left:480px;} 188 | .prepend-13 {padding-left:520px;} 189 | .prepend-14 {padding-left:560px;} 190 | .prepend-15 {padding-left:600px;} 191 | .prepend-16 {padding-left:640px;} 192 | .prepend-17 {padding-left:680px;} 193 | .prepend-18 {padding-left:720px;} 194 | .prepend-19 {padding-left:760px;} 195 | .prepend-20 {padding-left:800px;} 196 | .prepend-21 {padding-left:840px;} 197 | .prepend-22 {padding-left:880px;} 198 | .prepend-23 {padding-left:920px;} 199 | .border {padding-right:4px;margin-right:5px;border-right:1px solid #eee;} 200 | .colborder {padding-right:24px;margin-right:25px;border-right:1px solid #eee;} 201 | .pull-1 {margin-left:-40px;} 202 | .pull-2 {margin-left:-80px;} 203 | .pull-3 {margin-left:-120px;} 204 | .pull-4 {margin-left:-160px;} 205 | .pull-5 {margin-left:-200px;} 206 | .pull-6 {margin-left:-240px;} 207 | .pull-7 {margin-left:-280px;} 208 | .pull-8 {margin-left:-320px;} 209 | .pull-9 {margin-left:-360px;} 210 | .pull-10 {margin-left:-400px;} 211 | .pull-11 {margin-left:-440px;} 212 | .pull-12 {margin-left:-480px;} 213 | .pull-13 {margin-left:-520px;} 214 | .pull-14 {margin-left:-560px;} 215 | .pull-15 {margin-left:-600px;} 216 | .pull-16 {margin-left:-640px;} 217 | .pull-17 {margin-left:-680px;} 218 | .pull-18 {margin-left:-720px;} 219 | .pull-19 {margin-left:-760px;} 220 | .pull-20 {margin-left:-800px;} 221 | .pull-21 {margin-left:-840px;} 222 | .pull-22 {margin-left:-880px;} 223 | .pull-23 {margin-left:-920px;} 224 | .pull-24 {margin-left:-960px;} 225 | .pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float:left;position:relative;} 226 | .push-1 {margin:0 -40px 1.5em 40px;} 227 | .push-2 {margin:0 -80px 1.5em 80px;} 228 | .push-3 {margin:0 -120px 1.5em 120px;} 229 | .push-4 {margin:0 -160px 1.5em 160px;} 230 | .push-5 {margin:0 -200px 1.5em 200px;} 231 | .push-6 {margin:0 -240px 1.5em 240px;} 232 | .push-7 {margin:0 -280px 1.5em 280px;} 233 | .push-8 {margin:0 -320px 1.5em 320px;} 234 | .push-9 {margin:0 -360px 1.5em 360px;} 235 | .push-10 {margin:0 -400px 1.5em 400px;} 236 | .push-11 {margin:0 -440px 1.5em 440px;} 237 | .push-12 {margin:0 -480px 1.5em 480px;} 238 | .push-13 {margin:0 -520px 1.5em 520px;} 239 | .push-14 {margin:0 -560px 1.5em 560px;} 240 | .push-15 {margin:0 -600px 1.5em 600px;} 241 | .push-16 {margin:0 -640px 1.5em 640px;} 242 | .push-17 {margin:0 -680px 1.5em 680px;} 243 | .push-18 {margin:0 -720px 1.5em 720px;} 244 | .push-19 {margin:0 -760px 1.5em 760px;} 245 | .push-20 {margin:0 -800px 1.5em 800px;} 246 | .push-21 {margin:0 -840px 1.5em 840px;} 247 | .push-22 {margin:0 -880px 1.5em 880px;} 248 | .push-23 {margin:0 -920px 1.5em 920px;} 249 | .push-24 {margin:0 -960px 1.5em 960px;} 250 | .push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float:right;position:relative;} 251 | .prepend-top {margin-top:1.5em;} 252 | .append-bottom {margin-bottom:1.5em;} 253 | .box {padding:1.5em;margin-bottom:1.5em;background:#E5ECF9;} 254 | hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;} 255 | hr.space {background:#fff;color:#fff;visibility:hidden;} 256 | .clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;} 257 | .clearfix, .container {display:block;} 258 | .clear {clear:both;} -------------------------------------------------------------------------------- /public/stylesheets/blueprint/src/forms.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | forms.css 4 | * Sets up some default styling for forms 5 | * Gives you classes to enhance your forms 6 | 7 | Usage: 8 | * For text fields, use class .title or .text 9 | * For inline forms, use .inline (even when using columns) 10 | 11 | -------------------------------------------------------------- */ 12 | 13 | label { font-weight: bold; } 14 | fieldset { padding:1.4em; margin: 0 0 1.5em 0; border: 1px solid #ccc; } 15 | legend { font-weight: bold; font-size:1.2em; } 16 | 17 | 18 | /* Form fields 19 | -------------------------------------------------------------- */ 20 | 21 | input[type=text], input[type=password], 22 | input.text, input.title, 23 | textarea, select { 24 | background-color:#fff; 25 | border:1px solid #bbb; 26 | } 27 | input[type=text]:focus, input[type=password]:focus, 28 | input.text:focus, input.title:focus, 29 | textarea:focus, select:focus { 30 | border-color:#666; 31 | } 32 | 33 | input[type=text], input[type=password], 34 | input.text, input.title, 35 | textarea, select { 36 | margin:0.5em 0; 37 | } 38 | 39 | input.text, 40 | input.title { width: 300px; padding:5px; } 41 | input.title { font-size:1.5em; } 42 | textarea { width: 390px; height: 250px; padding:5px; } 43 | 44 | input[type=checkbox], input[type=radio], 45 | input.checkbox, input.radio { 46 | position:relative; top:.25em; 47 | } 48 | 49 | form.inline { line-height:3; } 50 | form.inline p { margin-bottom:0; } 51 | 52 | 53 | /* Success, notice and error boxes 54 | -------------------------------------------------------------- */ 55 | 56 | .error, 57 | .notice, 58 | .success { padding: .8em; margin-bottom: 1em; border: 2px solid #ddd; } 59 | 60 | .error { background: #FBE3E4; color: #8a1f11; border-color: #FBC2C4; } 61 | .notice { background: #FFF6BF; color: #514721; border-color: #FFD324; } 62 | .success { background: #E6EFC2; color: #264409; border-color: #C6D880; } 63 | .error a { color: #8a1f11; } 64 | .notice a { color: #514721; } 65 | .success a { color: #264409; } 66 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/src/grid.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | grid.css 4 | * Sets up an easy-to-use grid of 24 columns. 5 | 6 | By default, the grid is 950px wide, with 24 columns 7 | spanning 30px, and a 10px margin between columns. 8 | 9 | If you need fewer or more columns, namespaces or semantic 10 | element names, use the compressor script (lib/compress.rb) 11 | 12 | -------------------------------------------------------------- */ 13 | 14 | /* A container should group all your columns. */ 15 | .container { 16 | width: 950px; 17 | margin: 0 auto; 18 | } 19 | 20 | /* Use this class on any .span / container to see the grid. */ 21 | .showgrid { 22 | background: url(src/grid.png); 23 | } 24 | 25 | 26 | /* Columns 27 | -------------------------------------------------------------- */ 28 | 29 | /* Sets up basic grid floating and margin. */ 30 | .column, .span-1, .span-2, .span-3, .span-4, .span-5, .span-6, .span-7, .span-8, .span-9, .span-10, .span-11, .span-12, .span-13, .span-14, .span-15, .span-16, .span-17, .span-18, .span-19, .span-20, .span-21, .span-22, .span-23, .span-24 { 31 | float: left; 32 | margin-right: 10px; 33 | } 34 | 35 | /* The last column in a row needs this class. */ 36 | .last { margin-right: 0; } 37 | 38 | /* Use these classes to set the width of a column. */ 39 | .span-1 {width: 30px;} 40 | 41 | .span-2 {width: 70px;} 42 | .span-3 {width: 110px;} 43 | .span-4 {width: 150px;} 44 | .span-5 {width: 190px;} 45 | .span-6 {width: 230px;} 46 | .span-7 {width: 270px;} 47 | .span-8 {width: 310px;} 48 | .span-9 {width: 350px;} 49 | .span-10 {width: 390px;} 50 | .span-11 {width: 430px;} 51 | .span-12 {width: 470px;} 52 | .span-13 {width: 510px;} 53 | .span-14 {width: 550px;} 54 | .span-15 {width: 590px;} 55 | .span-16 {width: 630px;} 56 | .span-17 {width: 670px;} 57 | .span-18 {width: 710px;} 58 | .span-19 {width: 750px;} 59 | .span-20 {width: 790px;} 60 | .span-21 {width: 830px;} 61 | .span-22 {width: 870px;} 62 | .span-23 {width: 910px;} 63 | .span-24 {width:950px; margin-right:0;} 64 | 65 | /* Use these classes to set the width of an input. */ 66 | input.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 { 67 | border-left-width: 1px; 68 | border-right-width: 1px; 69 | padding-left: 5px; 70 | padding-right: 5px; 71 | } 72 | 73 | input.span-1, textarea.span-1 { width: 18px; } 74 | input.span-2, textarea.span-2 { width: 58px; } 75 | input.span-3, textarea.span-3 { width: 98px; } 76 | input.span-4, textarea.span-4 { width: 138px; } 77 | input.span-5, textarea.span-5 { width: 178px; } 78 | input.span-6, textarea.span-6 { width: 218px; } 79 | input.span-7, textarea.span-7 { width: 258px; } 80 | input.span-8, textarea.span-8 { width: 298px; } 81 | input.span-9, textarea.span-9 { width: 338px; } 82 | input.span-10, textarea.span-10 { width: 378px; } 83 | input.span-11, textarea.span-11 { width: 418px; } 84 | input.span-12, textarea.span-12 { width: 458px; } 85 | input.span-13, textarea.span-13 { width: 498px; } 86 | input.span-14, textarea.span-14 { width: 538px; } 87 | input.span-15, textarea.span-15 { width: 578px; } 88 | input.span-16, textarea.span-16 { width: 618px; } 89 | input.span-17, textarea.span-17 { width: 658px; } 90 | input.span-18, textarea.span-18 { width: 698px; } 91 | input.span-19, textarea.span-19 { width: 738px; } 92 | input.span-20, textarea.span-20 { width: 778px; } 93 | input.span-21, textarea.span-21 { width: 818px; } 94 | input.span-22, textarea.span-22 { width: 858px; } 95 | input.span-23, textarea.span-23 { width: 898px; } 96 | input.span-24, textarea.span-24 { width: 938px; } 97 | 98 | /* Add these to a column to append empty cols. */ 99 | 100 | .append-1 { padding-right: 40px;} 101 | .append-2 { padding-right: 80px;} 102 | .append-3 { padding-right: 120px;} 103 | .append-4 { padding-right: 160px;} 104 | .append-5 { padding-right: 200px;} 105 | .append-6 { padding-right: 240px;} 106 | .append-7 { padding-right: 280px;} 107 | .append-8 { padding-right: 320px;} 108 | .append-9 { padding-right: 360px;} 109 | .append-10 { padding-right: 400px;} 110 | .append-11 { padding-right: 440px;} 111 | .append-12 { padding-right: 480px;} 112 | .append-13 { padding-right: 520px;} 113 | .append-14 { padding-right: 560px;} 114 | .append-15 { padding-right: 600px;} 115 | .append-16 { padding-right: 640px;} 116 | .append-17 { padding-right: 680px;} 117 | .append-18 { padding-right: 720px;} 118 | .append-19 { padding-right: 760px;} 119 | .append-20 { padding-right: 800px;} 120 | .append-21 { padding-right: 840px;} 121 | .append-22 { padding-right: 880px;} 122 | .append-23 { padding-right: 920px;} 123 | 124 | /* Add these to a column to prepend empty cols. */ 125 | 126 | .prepend-1 { padding-left: 40px;} 127 | .prepend-2 { padding-left: 80px;} 128 | .prepend-3 { padding-left: 120px;} 129 | .prepend-4 { padding-left: 160px;} 130 | .prepend-5 { padding-left: 200px;} 131 | .prepend-6 { padding-left: 240px;} 132 | .prepend-7 { padding-left: 280px;} 133 | .prepend-8 { padding-left: 320px;} 134 | .prepend-9 { padding-left: 360px;} 135 | .prepend-10 { padding-left: 400px;} 136 | .prepend-11 { padding-left: 440px;} 137 | .prepend-12 { padding-left: 480px;} 138 | .prepend-13 { padding-left: 520px;} 139 | .prepend-14 { padding-left: 560px;} 140 | .prepend-15 { padding-left: 600px;} 141 | .prepend-16 { padding-left: 640px;} 142 | .prepend-17 { padding-left: 680px;} 143 | .prepend-18 { padding-left: 720px;} 144 | .prepend-19 { padding-left: 760px;} 145 | .prepend-20 { padding-left: 800px;} 146 | .prepend-21 { padding-left: 840px;} 147 | .prepend-22 { padding-left: 880px;} 148 | .prepend-23 { padding-left: 920px;} 149 | 150 | 151 | /* Border on right hand side of a column. */ 152 | .border { 153 | padding-right: 4px; 154 | margin-right: 5px; 155 | border-right: 1px solid #eee; 156 | } 157 | 158 | /* Border with more whitespace, spans one column. */ 159 | .colborder { 160 | padding-right: 24px; 161 | margin-right: 25px; 162 | border-right: 1px solid #eee; 163 | } 164 | 165 | 166 | /* Use these classes on an element to push it into the 167 | next column, or to pull it into the previous column. */ 168 | 169 | 170 | .pull-1 { margin-left: -40px; } 171 | .pull-2 { margin-left: -80px; } 172 | .pull-3 { margin-left: -120px; } 173 | .pull-4 { margin-left: -160px; } 174 | .pull-5 { margin-left: -200px; } 175 | .pull-6 { margin-left: -240px; } 176 | .pull-7 { margin-left: -280px; } 177 | .pull-8 { margin-left: -320px; } 178 | .pull-9 { margin-left: -360px; } 179 | .pull-10 { margin-left: -400px; } 180 | .pull-11 { margin-left: -440px; } 181 | .pull-12 { margin-left: -480px; } 182 | .pull-13 { margin-left: -520px; } 183 | .pull-14 { margin-left: -560px; } 184 | .pull-15 { margin-left: -600px; } 185 | .pull-16 { margin-left: -640px; } 186 | .pull-17 { margin-left: -680px; } 187 | .pull-18 { margin-left: -720px; } 188 | .pull-19 { margin-left: -760px; } 189 | .pull-20 { margin-left: -800px; } 190 | .pull-21 { margin-left: -840px; } 191 | .pull-22 { margin-left: -880px; } 192 | .pull-23 { margin-left: -920px; } 193 | .pull-24 { margin-left: -960px; } 194 | 195 | .pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float: left; position:relative;} 196 | 197 | 198 | .push-1 { margin: 0 -40px 1.5em 40px; } 199 | .push-2 { margin: 0 -80px 1.5em 80px; } 200 | .push-3 { margin: 0 -120px 1.5em 120px; } 201 | .push-4 { margin: 0 -160px 1.5em 160px; } 202 | .push-5 { margin: 0 -200px 1.5em 200px; } 203 | .push-6 { margin: 0 -240px 1.5em 240px; } 204 | .push-7 { margin: 0 -280px 1.5em 280px; } 205 | .push-8 { margin: 0 -320px 1.5em 320px; } 206 | .push-9 { margin: 0 -360px 1.5em 360px; } 207 | .push-10 { margin: 0 -400px 1.5em 400px; } 208 | .push-11 { margin: 0 -440px 1.5em 440px; } 209 | .push-12 { margin: 0 -480px 1.5em 480px; } 210 | .push-13 { margin: 0 -520px 1.5em 520px; } 211 | .push-14 { margin: 0 -560px 1.5em 560px; } 212 | .push-15 { margin: 0 -600px 1.5em 600px; } 213 | .push-16 { margin: 0 -640px 1.5em 640px; } 214 | .push-17 { margin: 0 -680px 1.5em 680px; } 215 | .push-18 { margin: 0 -720px 1.5em 720px; } 216 | .push-19 { margin: 0 -760px 1.5em 760px; } 217 | .push-20 { margin: 0 -800px 1.5em 800px; } 218 | .push-21 { margin: 0 -840px 1.5em 840px; } 219 | .push-22 { margin: 0 -880px 1.5em 880px; } 220 | .push-23 { margin: 0 -920px 1.5em 920px; } 221 | .push-24 { margin: 0 -960px 1.5em 960px; } 222 | 223 | .push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float: right; position:relative;} 224 | 225 | 226 | /* Misc classes and elements 227 | -------------------------------------------------------------- */ 228 | 229 | /* In case you need to add a gutter above/below an element */ 230 | .prepend-top { 231 | margin-top:1.5em; 232 | } 233 | .append-bottom { 234 | margin-bottom:1.5em; 235 | } 236 | 237 | /* Use a .box to create a padded box inside a column. */ 238 | .box { 239 | padding: 1.5em; 240 | margin-bottom: 1.5em; 241 | background: #E5ECF9; 242 | } 243 | 244 | /* Use this to create a horizontal ruler across a column. */ 245 | hr { 246 | background: #ddd; 247 | color: #ddd; 248 | clear: both; 249 | float: none; 250 | width: 100%; 251 | height: .1em; 252 | margin: 0 0 1.45em; 253 | border: none; 254 | } 255 | 256 | hr.space { 257 | background: #fff; 258 | color: #fff; 259 | visibility: hidden; 260 | } 261 | 262 | 263 | /* Clearing floats without extra markup 264 | Based on How To Clear Floats Without Structural Markup by PiE 265 | [http://www.positioniseverything.net/easyclearing.html] */ 266 | 267 | .clearfix:after, .container:after { 268 | content: "\0020"; 269 | display: block; 270 | height: 0; 271 | clear: both; 272 | visibility: hidden; 273 | overflow:hidden; 274 | } 275 | .clearfix, .container {display: block;} 276 | 277 | /* Regular clearing 278 | apply to column that should drop below previous ones. */ 279 | 280 | .clear { clear:both; } 281 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/src/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/public/stylesheets/blueprint/src/grid.png -------------------------------------------------------------------------------- /public/stylesheets/blueprint/src/ie.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | ie.css 4 | 5 | Contains every hack for Internet Explorer, 6 | so that our core files stay sweet and nimble. 7 | 8 | -------------------------------------------------------------- */ 9 | 10 | /* Make sure the layout is centered in IE5 */ 11 | body { text-align: center; } 12 | .container { text-align: left; } 13 | 14 | /* Fixes IE margin bugs */ 15 | * html .column, * html .span-1, * html .span-2, 16 | * html .span-3, * html .span-4, * html .span-5, 17 | * html .span-6, * html .span-7, * html .span-8, 18 | * html .span-9, * html .span-10, * html .span-11, 19 | * html .span-12, * html .span-13, * html .span-14, 20 | * html .span-15, * html .span-16, * html .span-17, 21 | * html .span-18, * html .span-19, * html .span-20, 22 | * html .span-21, * html .span-22, * html .span-23, 23 | * html .span-24 { display:inline; overflow-x: hidden; } 24 | 25 | 26 | /* Elements 27 | -------------------------------------------------------------- */ 28 | 29 | /* Fixes incorrect styling of legend in IE6. */ 30 | * html legend { margin:0px -8px 16px 0; padding:0; } 31 | 32 | /* Fixes wrong line-height on sup/sub in IE. */ 33 | sup { vertical-align:text-top; } 34 | sub { vertical-align:text-bottom; } 35 | 36 | /* Fixes IE7 missing wrapping of code elements. */ 37 | html>body p code { *white-space: normal; } 38 | 39 | /* IE 6&7 has problems with setting proper
    margins. */ 40 | hr { margin:-8px auto 11px; } 41 | 42 | /* Explicitly set interpolation, allowing dynamically resized images to not look horrible */ 43 | img { -ms-interpolation-mode:bicubic; } 44 | 45 | /* Clearing 46 | -------------------------------------------------------------- */ 47 | 48 | /* Makes clearfix actually work in IE */ 49 | .clearfix, .container { display:inline-block; } 50 | * html .clearfix, 51 | * html .container { height:1%; } 52 | 53 | 54 | /* Forms 55 | -------------------------------------------------------------- */ 56 | 57 | /* Fixes padding on fieldset */ 58 | fieldset { padding-top:0; } 59 | 60 | /* Makes classic textareas in IE 6 resemble other browsers */ 61 | textarea { overflow:auto; } 62 | 63 | /* Fixes rule that IE 6 ignores */ 64 | input.text, input.title, textarea { background-color:#fff; border:1px solid #bbb; } 65 | input.text:focus, input.title:focus { border-color:#666; } 66 | input.text, input.title, textarea, select { margin:0.5em 0; } 67 | input.checkbox, input.radio { position:relative; top:.25em; } 68 | 69 | /* Fixes alignment of inline form elements */ 70 | form.inline div, form.inline p { vertical-align:middle; } 71 | form.inline label { position:relative;top:-0.25em; } 72 | form.inline input.checkbox, form.inline input.radio, 73 | form.inline input.button, form.inline button { 74 | margin:0.5em 0; 75 | } 76 | button, input.button { position:relative;top:0.25em; } 77 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/src/print.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | print.css 4 | * Gives you some sensible styles for printing pages. 5 | * See Readme file in this directory for further instructions. 6 | 7 | Some additions you'll want to make, customized to your markup: 8 | #header, #footer, #navigation { display:none; } 9 | 10 | -------------------------------------------------------------- */ 11 | 12 | body { 13 | line-height: 1.5; 14 | font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; 15 | color:#000; 16 | background: none; 17 | font-size: 10pt; 18 | } 19 | 20 | 21 | /* Layout 22 | -------------------------------------------------------------- */ 23 | 24 | .container { 25 | background: none; 26 | } 27 | 28 | hr { 29 | background:#ccc; 30 | color:#ccc; 31 | width:100%; 32 | height:2px; 33 | margin:2em 0; 34 | padding:0; 35 | border:none; 36 | } 37 | hr.space { 38 | background: #fff; 39 | color: #fff; 40 | visibility: hidden; 41 | } 42 | 43 | 44 | /* Text 45 | -------------------------------------------------------------- */ 46 | 47 | h1,h2,h3,h4,h5,h6 { font-family: "Helvetica Neue", Arial, "Lucida Grande", sans-serif; } 48 | code { font:.9em "Courier New", Monaco, Courier, monospace; } 49 | 50 | a img { border:none; } 51 | p img.top { margin-top: 0; } 52 | 53 | blockquote { 54 | margin:1.5em; 55 | padding:1em; 56 | font-style:italic; 57 | font-size:.9em; 58 | } 59 | 60 | .small { font-size: .9em; } 61 | .large { font-size: 1.1em; } 62 | .quiet { color: #999; } 63 | .hide { display:none; } 64 | 65 | 66 | /* Links 67 | -------------------------------------------------------------- */ 68 | 69 | a:link, a:visited { 70 | background: transparent; 71 | font-weight:700; 72 | text-decoration: underline; 73 | } 74 | 75 | a:link:after, a:visited:after { 76 | content: " (" attr(href) ")"; 77 | font-size: 90%; 78 | } 79 | 80 | /* If you're having trouble printing relative links, uncomment and customize this: 81 | (note: This is valid CSS3, but it still won't go through the W3C CSS Validator) */ 82 | 83 | /* a[href^="/"]:after { 84 | content: " (http://www.yourdomain.com" attr(href) ") "; 85 | } */ 86 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/src/reset.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | reset.css 4 | * Resets default browser CSS. 5 | 6 | -------------------------------------------------------------- */ 7 | 8 | html, body, div, span, object, iframe, 9 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 10 | a, abbr, acronym, address, code, 11 | del, dfn, em, img, q, dl, dt, dd, ol, ul, li, 12 | fieldset, form, label, legend, 13 | table, caption, tbody, tfoot, thead, tr, th, td, 14 | article, aside, dialog, figure, footer, header, 15 | hgroup, nav, section { 16 | margin: 0; 17 | padding: 0; 18 | border: 0; 19 | font-weight: inherit; 20 | font-style: inherit; 21 | font-size: 100%; 22 | font-family: inherit; 23 | vertical-align: baseline; 24 | } 25 | 26 | article, aside, dialog, figure, footer, header, 27 | hgroup, nav, section { 28 | display:block; 29 | } 30 | 31 | body { 32 | line-height: 1.5; 33 | } 34 | 35 | /* Tables still need 'cellspacing="0"' in the markup. */ 36 | table { border-collapse: separate; border-spacing: 0; } 37 | caption, th, td { text-align: left; font-weight: normal; } 38 | table, td, th { vertical-align: middle; } 39 | 40 | /* Remove possible quote marks (") from ,
    . */ 41 | blockquote:before, blockquote:after, q:before, q:after { content: ""; } 42 | blockquote, q { quotes: "" ""; } 43 | 44 | /* Remove annoying border on linked images. */ 45 | a img { border: none; } 46 | -------------------------------------------------------------------------------- /public/stylesheets/blueprint/src/typography.css: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------- 2 | 3 | typography.css 4 | * Sets up some sensible default typography. 5 | 6 | -------------------------------------------------------------- */ 7 | 8 | /* Default font settings. 9 | The font-size percentage is of 16px. (0.75 * 16px = 12px) */ 10 | html { font-size:100.01%; } 11 | body { 12 | font-size: 75%; 13 | color: #222; 14 | background: #fff; 15 | font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; 16 | } 17 | 18 | 19 | /* Headings 20 | -------------------------------------------------------------- */ 21 | 22 | h1,h2,h3,h4,h5,h6 { font-weight: normal; color: #111; } 23 | 24 | h1 { font-size: 3em; line-height: 1; margin-bottom: 0.5em; } 25 | h2 { font-size: 2em; margin-bottom: 0.75em; } 26 | h3 { font-size: 1.5em; line-height: 1; margin-bottom: 1em; } 27 | h4 { font-size: 1.2em; line-height: 1.25; margin-bottom: 1.25em; } 28 | h5 { font-size: 1em; font-weight: bold; margin-bottom: 1.5em; } 29 | h6 { font-size: 1em; font-weight: bold; } 30 | 31 | h1 img, h2 img, h3 img, 32 | h4 img, h5 img, h6 img { 33 | margin: 0; 34 | } 35 | 36 | 37 | /* Text elements 38 | -------------------------------------------------------------- */ 39 | 40 | p { margin: 0 0 1.5em; } 41 | p img.left { float: left; margin: 1.5em 1.5em 1.5em 0; padding: 0; } 42 | p img.right { float: right; margin: 1.5em 0 1.5em 1.5em; } 43 | 44 | a:focus, 45 | a:hover { color: #000; } 46 | a { color: #009; text-decoration: underline; } 47 | 48 | blockquote { margin: 1.5em; color: #666; font-style: italic; } 49 | strong { font-weight: bold; } 50 | em,dfn { font-style: italic; } 51 | dfn { font-weight: bold; } 52 | sup, sub { line-height: 0; } 53 | 54 | abbr, 55 | acronym { border-bottom: 1px dotted #666; } 56 | address { margin: 0 0 1.5em; font-style: italic; } 57 | del { color:#666; } 58 | 59 | pre { margin: 1.5em 0; white-space: pre; } 60 | pre,code,tt { font: 1em 'andale mono', 'lucida console', monospace; line-height: 1.5; } 61 | 62 | 63 | /* Lists 64 | -------------------------------------------------------------- */ 65 | 66 | li ul, 67 | li ol { margin: 0; } 68 | ul, ol { margin: 0 1.5em 1.5em 0; padding-left: 3.333em; } 69 | 70 | ul { list-style-type: disc; } 71 | ol { list-style-type: decimal; } 72 | 73 | dl { margin: 0 0 1.5em 0; } 74 | dl dt { font-weight: bold; } 75 | dd { margin-left: 1.5em;} 76 | 77 | 78 | /* Tables 79 | -------------------------------------------------------------- */ 80 | 81 | table { margin-bottom: 1.4em; width:100%; } 82 | th { font-weight: bold; } 83 | thead th { background: #c3d9ff; } 84 | th,td,caption { padding: 4px 10px 4px 5px; } 85 | tr.even td { background: #e5ecf9; } 86 | tfoot { font-style: italic; } 87 | caption { background: #eee; } 88 | 89 | 90 | /* Misc classes 91 | -------------------------------------------------------------- */ 92 | 93 | .small { font-size: .8em; margin-bottom: 1.875em; line-height: 1.875em; } 94 | .large { font-size: 1.2em; line-height: 2.5em; margin-bottom: 1.25em; } 95 | .hide { display: none; } 96 | 97 | .quiet { color: #666; } 98 | .loud { color: #000; } 99 | .highlight { background:#ff0; } 100 | .added { background:#060; color: #fff; } 101 | .removed { background:#900; color: #fff; } 102 | 103 | .first { margin-left:0; padding-left:0; } 104 | .last { margin-right:0; padding-right:0; } 105 | .top { margin-top:0; padding-top:0; } 106 | .bottom { margin-bottom:0; padding-bottom:0; } 107 | -------------------------------------------------------------------------------- /public/stylesheets/custom.css: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 710px; 3 | } 4 | 5 | body { 6 | background: #cff; 7 | } 8 | 9 | header { 10 | padding-top: 20px; 11 | } 12 | 13 | header img { 14 | padding: 1em; 15 | background: #fff; 16 | } 17 | 18 | section { 19 | margin-top: 1em; 20 | font-size: 120%; 21 | padding: 20px; 22 | background: #fff; 23 | } 24 | 25 | section h1 { 26 | font-size: 200%; 27 | } 28 | 29 | /* Links */ 30 | 31 | a { 32 | color: #09c; 33 | text-decoration: none; 34 | } 35 | 36 | a:hover { 37 | color: #069; 38 | text-decoration: underline; 39 | } 40 | 41 | a:visited { 42 | color: #069; 43 | } 44 | 45 | /* Navigation */ 46 | 47 | nav { 48 | float: right; 49 | background: white; 50 | padding: 0 0.7em; 51 | white-space: nowrap; 52 | } 53 | 54 | nav ul { 55 | margin: 0; 56 | padding: 0; 57 | } 58 | 59 | nav ul li { 60 | list-style-type: none; 61 | display: inline-block; 62 | padding: 0.2em 0; 63 | } 64 | 65 | nav ul li a { 66 | padding: 0 5px; 67 | font-weight: bold; 68 | } 69 | 70 | nav ul li a:visited { 71 | color: #09c; 72 | } 73 | 74 | nav ul li a:hover { 75 | text-decoration: underline; 76 | } 77 | 78 | /* Sign up button */ 79 | 80 | a.signup_button { 81 | margin-left: auto; 82 | margin-right: auto; 83 | display: block; 84 | text-align: center; 85 | width: 190px; 86 | color: #fff; 87 | background: #006400; 88 | font-size: 150%; 89 | font-weight: bold; 90 | padding: 20px; 91 | } 92 | 93 | /* Round corners */ 94 | 95 | .round { 96 | -moz-border-radius: 10px; 97 | -webkit-border-radius: 10px; 98 | border-radius: 10px; 99 | } 100 | 101 | /* Footer */ 102 | 103 | footer { 104 | text-align: center; 105 | margin-top: 10px; 106 | width: 710px; 107 | margin-left: auto; 108 | margin-right: auto; 109 | } 110 | 111 | footer nav { 112 | float: none; 113 | } 114 | 115 | /* User show page */ 116 | 117 | table.profile { 118 | width: 100%; 119 | margin-bottom: 0; 120 | } 121 | 122 | td.main { 123 | width: 70%; 124 | padding: 1em; 125 | } 126 | 127 | td.sidebar { 128 | width: 30%; 129 | padding: 1em; 130 | vertical-align: top; 131 | background: #ffc; 132 | } 133 | 134 | .profile img.gravatar { 135 | border: 1px solid #999; 136 | margin-bottom: -15px; 137 | } 138 | 139 | div.field, div.actions { 140 | margin-bottom: 10px; 141 | } 142 | 143 | /* Error messages */ 144 | 145 | .field_with_errors { 146 | margin-top: 10px; 147 | padding: 2px; 148 | background-color: red; 149 | display: table; 150 | } 151 | 152 | .field_with_errors label { 153 | color: #fff; 154 | } 155 | 156 | #error_explanation { 157 | width: 400px; 158 | border: 2px solid red; 159 | padding: 7px; 160 | padding-bottom: 12px; 161 | margin-bottom: 20px; 162 | background-color: #f0f0f0; 163 | } 164 | 165 | #error_explanation h2 { 166 | text-align: left; 167 | font-weight: bold; 168 | padding: 5px 5px 5px 15px; 169 | font-size: 12px; 170 | margin: -7px; 171 | background-color: #c00; 172 | color: #fff; 173 | } 174 | 175 | #error_explanation p { 176 | color: #333; 177 | margin-bottom: 0; 178 | padding: 5px; 179 | } 180 | 181 | #error_explanation ul li { 182 | font-size: 12px; 183 | list-style: square; 184 | } 185 | 186 | ul.users { 187 | margin-top: 1em; 188 | } 189 | 190 | ul.users li { 191 | list-style: none; 192 | } 193 | 194 | /* Micropost styling */ 195 | 196 | h1.micropost { 197 | margin-bottom: 0.3em; 198 | } 199 | 200 | table.microposts { 201 | margin-top: 1em; 202 | } 203 | 204 | table.microposts tr { 205 | height: 70px; 206 | } 207 | 208 | table.microposts tr td.gravatar { 209 | border-top: 1px solid #ccc; 210 | vertical-align: top; 211 | width: 50px; 212 | } 213 | 214 | table.microposts tr td.micropost { 215 | border-top: 1px solid #ccc; 216 | vertical-align: top; 217 | padding-top: 10px; 218 | } 219 | 220 | table.microposts tr td.micropost span.timestamp { 221 | display: block; 222 | font-size: 85%; 223 | color: #666; 224 | } 225 | 226 | div.user_info img { 227 | padding-right: 0.1em; 228 | } 229 | 230 | div.user_info a { 231 | text-decoration: none; 232 | } 233 | 234 | div.user_info span.user_name { 235 | position: absolute; 236 | } 237 | 238 | div.user_info span.microposts { 239 | font-size: 80%; 240 | } 241 | 242 | form.new_micropost { 243 | margin-bottom: 2em; 244 | } 245 | 246 | form.new_micropost textarea { 247 | height: 4em; 248 | margin-bottom: 0; 249 | } 250 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /spec/controllers/microposts_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe MicropostsController do 4 | render_views 5 | 6 | describe "access control" do 7 | it "should deny access to 'create'" do 8 | post :create 9 | response.should redirect_to(signin_path) 10 | end 11 | 12 | it "should deny access to 'destroy'" do 13 | delete :destroy, :id => 1 14 | response.should redirect_to(signin_path) 15 | end 16 | end 17 | 18 | describe "POST 'create'" do 19 | 20 | before(:each) do 21 | @user = test_sign_in(Factory(:user)) 22 | end 23 | 24 | describe "failure" do 25 | 26 | before(:each) do 27 | @attr = { :content => "" } 28 | end 29 | 30 | it "should not create a micropost" do 31 | lambda do 32 | post :create, :micropost => @attr 33 | end.should_not change(Micropost, :count) 34 | end 35 | 36 | it "should re-render the home page" do 37 | post :create, :micropost => @attr 38 | response.should render_template('pages/home') 39 | end 40 | end 41 | 42 | describe "success" do 43 | 44 | before(:each) do 45 | @attr = { :content => "Lorem ipsum dolor sit amet" } 46 | end 47 | 48 | it "should create a micropost" do 49 | lambda do 50 | post :create, :micropost => @attr 51 | end.should change(Micropost, :count).by(1) 52 | end 53 | 54 | it "should redirect to the root path" do 55 | post :create, :micropost => @attr 56 | response.should redirect_to(root_path) 57 | end 58 | 59 | it "should have a flash success message" do 60 | post :create, :micropost => @attr 61 | flash[:success].should =~ /micropost created/i 62 | end 63 | end 64 | end 65 | 66 | describe "DELETE 'destroy'" do 67 | 68 | describe "for an unauthorized user" do 69 | 70 | before(:each) do 71 | @user = Factory(:user) 72 | wrong_user = Factory(:user, :email => Factory.next(:email)) 73 | @micropost = Factory(:micropost, :user => @user) 74 | test_sign_in(wrong_user) 75 | end 76 | 77 | it "should deny access" do 78 | delete :destroy, :id => @micropost 79 | response.should redirect_to(root_path) 80 | end 81 | end 82 | 83 | describe "for an authorized user" do 84 | 85 | before(:each) do 86 | @user = test_sign_in(Factory(:user)) 87 | @micropost = Factory(:micropost, :user => @user) 88 | end 89 | 90 | it "should destroy the micropost" do 91 | lambda do 92 | delete :destroy, :id => @micropost 93 | flash[:success].should =~ /deleted/i 94 | response.should redirect_to(root_path) 95 | end.should change(Micropost, :count).by(-1) 96 | end 97 | end 98 | end 99 | end -------------------------------------------------------------------------------- /spec/controllers/pages_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe PagesController do 4 | render_views 5 | 6 | before(:each) do 7 | @base_title = "Ruby on Rails Tutorial Sample App" 8 | end 9 | 10 | describe "GET 'home'" do 11 | 12 | describe "when not signed in" do 13 | it "should be successful" do 14 | get 'home' 15 | response.should be_success 16 | end 17 | 18 | it "should have the right title" do 19 | get 'home' 20 | response.should have_selector("title", 21 | :content => "#{@base_title} | Home") 22 | end 23 | 24 | it "should have a non-blank body" do 25 | get 'home' 26 | response.body.should_not =~ /\s*<\/body>/ 27 | end 28 | end 29 | 30 | describe "when signed in" do 31 | before(:each) do 32 | @user = test_sign_in(Factory(:user)) 33 | other_user = Factory(:user, :email => Factory.next(:email)) 34 | other_user.follow!(@user) 35 | end 36 | 37 | it "should have the right follower/following counts" do 38 | get :home 39 | response.should have_selector('a', :href => following_user_path(@user), 40 | :content => "0 following") 41 | response.should have_selector('a', :href => followers_user_path(@user), 42 | :content => "1 follower") 43 | end 44 | end 45 | 46 | end 47 | 48 | describe "GET 'contact'" do 49 | it "should be successful" do 50 | get 'contact' 51 | response.should be_success 52 | end 53 | 54 | it "should have the right title" do 55 | get 'contact' 56 | response.should have_selector("title", 57 | :content => "#{@base_title} | Contact") 58 | end 59 | end 60 | 61 | describe "GET 'about'" do 62 | it "should be successful" do 63 | get 'about' 64 | response.should be_success 65 | end 66 | 67 | it "should have the right title" do 68 | get 'about' 69 | response.should have_selector("title", 70 | :content => "#{@base_title} | About") 71 | end 72 | end 73 | 74 | describe "GET 'help'" do 75 | it "should be successful" do 76 | get 'help' 77 | response.should be_success 78 | end 79 | 80 | it "should have the right title" do 81 | get 'help' 82 | response.should have_selector("title", 83 | :content => "#{@base_title} | Help") 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /spec/controllers/relationships_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe RelationshipsController do 4 | 5 | describe "access control" do 6 | it "should require signin for create" do 7 | post :create 8 | response.should redirect_to(signin_path) 9 | end 10 | 11 | it "should require signin for destroy" do 12 | delete :destroy, :id => 1 13 | response.should redirect_to(signin_path) 14 | end 15 | end 16 | 17 | describe "POST 'create'" do 18 | 19 | before(:each) do 20 | @user = test_sign_in(Factory(:user)) 21 | @followed = Factory(:user, :email => Factory.next(:email)) 22 | end 23 | 24 | it "should create a relationship" do 25 | lambda do 26 | post :create, :relationship => { :followed_id => @followed } 27 | response.should redirect_to(user_path(@followed)) 28 | end.should change(Relationship, :count).by(1) 29 | end 30 | 31 | it "should create a relationship with Ajax" do 32 | lambda do 33 | xhr :post, :create, :relationship => { :followed_id => @followed } 34 | response.should be_success 35 | end.should change(Relationship, :count).by(1) 36 | end 37 | end 38 | 39 | describe "DELETE 'destroy'" do 40 | 41 | before(:each) do 42 | @user = test_sign_in(Factory(:user)) 43 | @followed = Factory(:user, :email => Factory.next(:email)) 44 | @user.follow!(@followed) 45 | @relationship = @user.relationships.find_by_followed_id(@followed) 46 | end 47 | 48 | it "should destroy a relationship" do 49 | lambda do 50 | delete :destroy, :id => @relationship 51 | response.should redirect_to(user_path(@followed)) 52 | end.should change(Relationship, :count).by(-1) 53 | end 54 | 55 | it "should destroy a relationship with Ajax" do 56 | lambda do 57 | xhr :delete, :destroy, :id => @relationship 58 | response.should be_success 59 | end.should change(Relationship, :count).by(-1) 60 | end 61 | end 62 | end -------------------------------------------------------------------------------- /spec/controllers/sessions_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SessionsController do 4 | render_views 5 | 6 | describe "GET 'new'" do 7 | it "should be successful" do 8 | get :new 9 | response.should be_success 10 | end 11 | 12 | it "should have the right title" do 13 | get :new 14 | response.should have_selector('title', :content => "Sign in") 15 | end 16 | end 17 | 18 | describe "POST 'create'" do 19 | 20 | describe "failure" do 21 | 22 | before(:each) do 23 | @attr = { :email => "", :password => "" } 24 | end 25 | 26 | it "should re-render the new page" do 27 | post :create, :session => @attr 28 | response.should render_template('new') 29 | end 30 | 31 | it "should have the right title" do 32 | post :create, :session => @attr 33 | response.should have_selector('title', :content => "Sign in") 34 | end 35 | 36 | it "should have an error message" do 37 | post :create, :session => @attr 38 | flash.now[:error].should =~ /invalid/i 39 | end 40 | end 41 | 42 | describe "success" do 43 | 44 | before(:each) do 45 | @user = Factory(:user) 46 | @attr = { :email => @user.email, :password => @user.password } 47 | end 48 | 49 | it "should sign the user in" do 50 | post :create, :session => @attr 51 | controller.current_user.should == @user 52 | controller.should be_signed_in 53 | end 54 | 55 | it "should redirect to the user show page" do 56 | post :create, :session => @attr 57 | response.should redirect_to(user_path(@user)) 58 | end 59 | end 60 | end 61 | 62 | describe "DELETE 'destroy'" do 63 | it "should sign a user out" do 64 | test_sign_in(Factory(:user)) 65 | delete :destroy 66 | controller.should_not be_signed_in 67 | response.should redirect_to(root_path) 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /spec/controllers/users_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe UsersController do 4 | render_views 5 | 6 | describe "GET 'index'" do 7 | 8 | describe "for non-signed-in users" do 9 | it "should deny access" do 10 | get :index 11 | response.should redirect_to(signin_path) 12 | end 13 | end 14 | 15 | describe "for signed-in-users" do 16 | 17 | before(:each) do 18 | @user = test_sign_in(Factory(:user)) 19 | second = Factory(:user, :name => "Bob", :email => "another@example.com") 20 | third = Factory(:user, :name => "Ben", :email => "another@example.net") 21 | 22 | 30.times do 23 | Factory(:user, :name => Factory.next(:name), 24 | :email => Factory.next(:email)) 25 | end 26 | end 27 | 28 | it "should be successful" do 29 | get :index 30 | response.should be_success 31 | end 32 | 33 | it "should have the right title" do 34 | get :index 35 | response.should have_selector('title', :content => "All users") 36 | end 37 | 38 | it "should have an element for each user" do 39 | get :index 40 | User.paginate(:page => 1).each do |user| 41 | response.should have_selector('li', :content => user.name) 42 | end 43 | end 44 | 45 | it "should paginate users" do 46 | get :index 47 | response.should have_selector('div.pagination') 48 | response.should have_selector('span.disabled', :content => "Previous") 49 | response.should have_selector('a', :href => "/users?page=2", 50 | :content => "2") 51 | response.should have_selector('a', :href => "/users?page=2", 52 | :content => "Next") 53 | end 54 | 55 | it "should have delete links for admins" do 56 | @user.toggle!(:admin) 57 | other_user = User.all.second 58 | get :index 59 | response.should have_selector('a', :href => user_path(other_user), 60 | :content => "delete") 61 | end 62 | 63 | it "should not have delete links for non-admins" do 64 | other_user = User.all.second 65 | get :index 66 | response.should_not have_selector('a', :href => user_path(other_user), 67 | :content => "delete") 68 | end 69 | end 70 | end 71 | 72 | describe "GET 'show'" do 73 | 74 | before(:each) do 75 | @user = Factory(:user) 76 | end 77 | 78 | it "should be successful" do 79 | get :show, :id => @user 80 | response.should be_success 81 | end 82 | 83 | it "should find the right user" do 84 | get :show, :id => @user 85 | assigns(:user).should == @user 86 | end 87 | 88 | it "should have the right title" do 89 | get :show, :id => @user 90 | response.should have_selector('title', :content => @user.name) 91 | end 92 | 93 | it "should have the user's name" do 94 | get :show, :id => @user 95 | response.should have_selector('h1', :content => @user.name) 96 | end 97 | 98 | it "should have a profile image" do 99 | get :show, :id => @user 100 | response.should have_selector('h1>img', :class => "gravatar") 101 | end 102 | 103 | it "should have the right URL" do 104 | get :show, :id => @user 105 | response.should have_selector('td>a', :content => user_path(@user), 106 | :href => user_path(@user)) 107 | end 108 | 109 | it "should show the user's microposts" do 110 | mp1 = Factory(:micropost, :user => @user, :content => "Foo bar") 111 | mp2 = Factory(:micropost, :user => @user, :content => "Baz quux") 112 | get :show, :id => @user 113 | response.should have_selector('span.content', :content => mp1.content) 114 | response.should have_selector('span.content', :content => mp2.content) 115 | end 116 | 117 | it "should paginate microposts" do 118 | 35.times { Factory(:micropost, :user => @user, :content => "foo") } 119 | get :show, :id => @user 120 | response.should have_selector('div.pagination') 121 | end 122 | 123 | it "should display the micropost count" do 124 | 10.times { Factory(:micropost, :user => @user, :content => "foo") } 125 | get :show, :id => @user 126 | response.should have_selector('td.sidebar', 127 | :content => @user.microposts.count.to_s) 128 | end 129 | 130 | describe "when signed in as another user" do 131 | it "should be successful" do 132 | test_sign_in(Factory(:user, :email => Factory.next(:email))) 133 | get :show, :id => @user 134 | response.should be_success 135 | end 136 | end 137 | end 138 | 139 | describe "GET 'new'" do 140 | 141 | it "should be successful" do 142 | get :new 143 | response.should be_success 144 | end 145 | 146 | it "should have the right title" do 147 | get :new 148 | response.should have_selector('title', :content => "Sign up") 149 | end 150 | end 151 | 152 | describe "POST 'create'" do 153 | 154 | describe "failure" do 155 | 156 | before(:each) do 157 | @attr = { :name => "", :email => "", :password => "", 158 | :password_confirmation => "" } 159 | end 160 | 161 | it "should have the right title" do 162 | post :create, :user => @attr 163 | response.should have_selector('title', :content => "Sign up") 164 | end 165 | 166 | it "should render the 'new' page" do 167 | post :create, :user => @attr 168 | response.should render_template('new') 169 | end 170 | 171 | it "should not create a user" do 172 | lambda do 173 | post :create, :user => @attr 174 | end.should_not change(User, :count) 175 | end 176 | end 177 | 178 | describe "success" do 179 | 180 | before(:each) do 181 | @attr = { :name => "New User", :email => "user@example.com", 182 | :password => "foobar", :password_confirmation => "foobar" } 183 | end 184 | 185 | it "should create a user" do 186 | lambda do 187 | post :create, :user => @attr 188 | end.should change(User, :count).by(1) 189 | end 190 | 191 | it "should redirect to the user show page" do 192 | post :create, :user => @attr 193 | response.should redirect_to(user_path(assigns(:user))) 194 | end 195 | 196 | it "should have a welcome message" do 197 | post :create, :user => @attr 198 | flash[:success].should =~ /welcome to the sample app/i 199 | end 200 | 201 | it "should sign the user in" do 202 | post :create, :user => @attr 203 | controller.should be_signed_in 204 | end 205 | end 206 | end 207 | 208 | describe "GET 'edit'" do 209 | 210 | before(:each) do 211 | @user = Factory(:user) 212 | test_sign_in(@user) 213 | end 214 | 215 | it "should be successful" do 216 | get :edit, :id => @user 217 | response.should be_success 218 | end 219 | 220 | it "should have the right title" do 221 | get :edit, :id => @user 222 | response.should have_selector('title', :content => "Edit user") 223 | end 224 | 225 | it "should have a link to change the Gravatar" do 226 | get :edit, :id => @user 227 | response.should have_selector('a', :href => 'http://gravatar.com/emails', 228 | :content => "change") 229 | end 230 | end 231 | 232 | describe "PUT 'update'" do 233 | 234 | before(:each) do 235 | @user = Factory(:user) 236 | test_sign_in(@user) 237 | end 238 | 239 | describe "failure" do 240 | 241 | before(:each) do 242 | @attr = { :name => "", :email => "", :password => "", 243 | :password_confirmation => "" } 244 | end 245 | 246 | it "should render the 'edit' page" do 247 | put :update, :id => @user, :user => @attr 248 | response.should render_template('edit') 249 | end 250 | 251 | it "should have the right title" do 252 | put :update, :id => @user, :user => @attr 253 | response.should have_selector('title', :content => "Edit user") 254 | end 255 | end 256 | 257 | describe "success" do 258 | 259 | before(:each) do 260 | @attr = { :name => "New Name", :email => "user@example.org", 261 | :password => "barbaz", :password_confirmation => "barbaz" } 262 | end 263 | 264 | it "should change the user's attributes" do 265 | put :update, :id => @user, :user => @attr 266 | @user.reload 267 | @user.name.should == @attr[:name] 268 | @user.email.should == @attr[:email] 269 | @user.encrypted_password.should == assigns(:user).encrypted_password 270 | end 271 | 272 | it "should have a flash message" do 273 | put :update, :id => @user, :user => @attr 274 | flash[:success].should =~ /updated/ 275 | end 276 | end 277 | end 278 | 279 | describe "authentication of edit/update actions" do 280 | 281 | before(:each) do 282 | @user = Factory(:user) 283 | end 284 | 285 | describe "for non-signed-in users" do 286 | 287 | it "should deny access to 'edit'" do 288 | get :edit, :id => @user 289 | response.should redirect_to(signin_path) 290 | flash[:notice].should =~ /sign in/i 291 | end 292 | 293 | it "should deny access to 'update'" do 294 | put :update, :id => @user, :user => {} 295 | response.should redirect_to(signin_path) 296 | end 297 | end 298 | 299 | describe "for signed-in users" do 300 | 301 | before(:each) do 302 | wrong_user = Factory(:user, :email => "user@example.net") 303 | test_sign_in(wrong_user) 304 | end 305 | 306 | it "should require matching users for 'edit'" do 307 | get :edit, :id => @user 308 | response.should redirect_to(root_path) 309 | end 310 | 311 | it "should require matching users for 'update'" do 312 | put :update, :id => @user, :user => {} 313 | response.should redirect_to(root_path) 314 | end 315 | end 316 | end 317 | 318 | describe "DELETE 'destroy'" do 319 | 320 | before(:each) do 321 | @user = Factory(:user) 322 | end 323 | 324 | describe "as a non-signed-in user" do 325 | it "should deny access" do 326 | delete :destroy, :id => @user 327 | response.should redirect_to(signin_path) 328 | end 329 | end 330 | 331 | describe "as non-admin user" do 332 | it "should protect the action" do 333 | test_sign_in(@user) 334 | delete :destroy, :id => @user 335 | response.should redirect_to(root_path) 336 | end 337 | end 338 | 339 | describe "as an admin user" do 340 | 341 | before(:each) do 342 | @admin = Factory(:user, :email => "admin@example.com", :admin => true) 343 | test_sign_in(@admin) 344 | end 345 | 346 | it "should destroy the user" do 347 | lambda do 348 | delete :destroy, :id => @user 349 | end.should change(User, :count).by(-1) 350 | end 351 | 352 | it "should redirect to the users page" do 353 | delete :destroy, :id => @user 354 | flash[:success].should =~ /destroyed/i 355 | response.should redirect_to(users_path) 356 | end 357 | 358 | it "should not be able to destroy itself" do 359 | lambda do 360 | delete :destroy, :id => @admin 361 | end.should_not change(User, :count) 362 | end 363 | end 364 | end 365 | 366 | describe "follow pages" do 367 | 368 | describe "when not signed in" do 369 | 370 | it "should protect 'following'" do 371 | get :following, :id => 1 372 | response.should redirect_to(signin_path) 373 | end 374 | 375 | it "should protect 'followers'" do 376 | get :followers, :id => 1 377 | response.should redirect_to(signin_path) 378 | end 379 | end 380 | 381 | describe "when signed in" do 382 | 383 | before(:each) do 384 | @user = test_sign_in(Factory(:user)) 385 | @other_user = Factory(:user, :email => Factory.next(:email)) 386 | @user.follow!(@other_user) 387 | end 388 | 389 | it "should show user following" do 390 | get :following, :id => @user 391 | response.should have_selector('a', :href => user_path(@other_user), 392 | :content => @other_user.name) 393 | end 394 | 395 | it "should show user followers" do 396 | get :followers, :id => @other_user 397 | response.should have_selector('a', :href => user_path(@user), 398 | :content => @user.name) 399 | end 400 | end 401 | end 402 | end 403 | -------------------------------------------------------------------------------- /spec/factories.rb: -------------------------------------------------------------------------------- 1 | Factory.define :user do |user| 2 | user.name "Michael Hartl" 3 | user.email "mhartl@example.com" 4 | user.password "foobar" 5 | user.password_confirmation "foobar" 6 | end 7 | 8 | Factory.sequence :email do |n| 9 | "person-#{n}@example.com" 10 | end 11 | 12 | Factory.sequence :name do |n| 13 | "Person #{n}" 14 | end 15 | 16 | Factory.define :micropost do |micropost| 17 | micropost.content "Foo bar" 18 | micropost.association :user 19 | end -------------------------------------------------------------------------------- /spec/models/micropost_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Micropost do 4 | 5 | before(:each) do 6 | @user = Factory(:user) 7 | @attr = { :content => "lorem ipsum" } 8 | end 9 | 10 | it "should create a new instance with valid attributes" do 11 | @user.microposts.create!(@attr) 12 | end 13 | 14 | describe "user associations" do 15 | 16 | before(:each) do 17 | @micropost = @user.microposts.create(@attr) 18 | end 19 | 20 | it "should have a user attribute" do 21 | @micropost.should respond_to(:user) 22 | end 23 | 24 | it "should have the right associated user" do 25 | @micropost.user_id.should == @user.id 26 | @micropost.user.should == @user 27 | end 28 | end 29 | 30 | describe "validations" do 31 | 32 | it "should have a user id" do 33 | Micropost.new(@attr).should_not be_valid 34 | end 35 | 36 | it "should require nonblank content" do 37 | @user.microposts.build(:content => " ").should_not be_valid 38 | end 39 | 40 | it "should reject long content" do 41 | @user.microposts.build(:content => "a" * 141).should_not be_valid 42 | end 43 | end 44 | 45 | describe "from_users_followed_by" do 46 | 47 | before(:each) do 48 | @other_user = Factory(:user, :email => Factory.next(:email)) 49 | @third_user = Factory(:user, :email => Factory.next(:email)) 50 | 51 | @user_post = @user.microposts.create!(:content => "foo") 52 | @other_post = @other_user.microposts.create!(:content => "bar") 53 | @third_post = @third_user.microposts.create!(:content => "baz") 54 | 55 | @user.follow!(@other_user) 56 | end 57 | 58 | it "should have a from_users_followed_by method" do 59 | Micropost.should respond_to(:from_users_followed_by) 60 | end 61 | 62 | it "should include the followed user's microposts" do 63 | Micropost.from_users_followed_by(@user).should include(@other_post) 64 | end 65 | 66 | it "should include the user's own microposts" do 67 | Micropost.from_users_followed_by(@user).should include(@user_post) 68 | end 69 | 70 | it "should not include an unfollowed user's microposts" do 71 | Micropost.from_users_followed_by(@user).should_not include(@third_post) 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /spec/models/relationship_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Relationship do 4 | 5 | before(:each) do 6 | @follower = Factory(:user) 7 | @followed = Factory(:user, :email => Factory.next(:email)) 8 | 9 | @attr = { :followed_id => @followed.id } 10 | end 11 | 12 | it "should create a new instance with valid attributes" do 13 | @follower.relationships.create!(@attr) 14 | end 15 | 16 | describe "follow methods" do 17 | 18 | before(:each) do 19 | @relationship = @follower.relationships.create!(@attr) 20 | end 21 | 22 | it "should have a follower attribute" do 23 | @relationship.should respond_to(:follower) 24 | end 25 | 26 | it "should have the right follower" do 27 | @relationship.follower.should == @follower 28 | end 29 | 30 | it "should have a followed attribute" do 31 | @relationship.should respond_to(:followed) 32 | end 33 | 34 | it "should have the right followed user" do 35 | @relationship.followed.should == @followed 36 | end 37 | end 38 | 39 | describe "validations" do 40 | 41 | it "should require a follower id" do 42 | Relationship.new(@attr).should_not be_valid 43 | end 44 | 45 | it "should require a followed id" do 46 | @follower.relationships.build.should_not be_valid 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe User do 4 | 5 | before(:each) do 6 | @attr = { 7 | :name => "Example User", 8 | :email => "user@example.com", 9 | :password => "foobar", 10 | :password_confirmation => "foobar" 11 | } 12 | end 13 | 14 | it "should create a new instance given a valid attribute" do 15 | User.create!(@attr) 16 | end 17 | 18 | it "should require a name" do 19 | no_name_user = User.new(@attr.merge(:name => "")) 20 | no_name_user.should_not be_valid 21 | end 22 | 23 | it "should require an email address" do 24 | no_email_user = User.new(@attr.merge(:email => "")) 25 | no_email_user.should_not be_valid 26 | end 27 | 28 | it "should reject names that are too long" do 29 | long_name = "a" * 51 30 | long_name_user = User.new(@attr.merge(:name => long_name)) 31 | long_name_user.should_not be_valid 32 | end 33 | 34 | it "should accept valid email addresses" do 35 | addresses = %w[user@foo.com THE_USER@foo.bar.org first.last@foo.jp] 36 | addresses.each do |address| 37 | valid_email_user = User.new(@attr.merge(:email => address)) 38 | valid_email_user.should be_valid 39 | end 40 | end 41 | 42 | it "should reject invalid email addresses" do 43 | addresses = %w[user@foo,com user_at_foo.org example.user@foo.] 44 | addresses.each do |address| 45 | invalid_email_user = User.new(@attr.merge(:email => address)) 46 | invalid_email_user.should_not be_valid 47 | end 48 | end 49 | 50 | it "should reject duplicate email addresses" do 51 | User.create!(@attr) 52 | user_with_duplicate_email = User.new(@attr) 53 | user_with_duplicate_email.should_not be_valid 54 | end 55 | 56 | it "should reject email addresses identical up to case" do 57 | upcased_email = @attr[:email].upcase 58 | User.create!(@attr.merge(:email => upcased_email)) 59 | user_with_duplicate_email = User.new(@attr) 60 | user_with_duplicate_email.should_not be_valid 61 | end 62 | 63 | describe "passwords" do 64 | 65 | before(:each) do 66 | @user = User.new(@attr) 67 | end 68 | 69 | it "should have a password attribute" do 70 | @user.should respond_to(:password) 71 | end 72 | 73 | it "should have a password confirmation attribute" do 74 | @user.should respond_to(:password_confirmation) 75 | end 76 | end 77 | 78 | describe "password validations" do 79 | 80 | it "should require a password" do 81 | User.new(@attr.merge(:password => "", :password_confirmation => "")). 82 | should_not be_valid 83 | end 84 | 85 | it "should require a matching password confirmation" do 86 | User.new(@attr.merge(:password_confirmation => "invalid")). 87 | should_not be_valid 88 | end 89 | 90 | it "should reject short passwords" do 91 | short = "a" * 5 92 | hash = @attr.merge(:password => short, :password_confirmation => short) 93 | User.new(hash).should_not be_valid 94 | end 95 | 96 | it "should reject long passwords" do 97 | long = "a" * 41 98 | hash = @attr.merge(:password => long, :password_confirmation => long) 99 | User.new(hash).should_not be_valid 100 | end 101 | end 102 | 103 | describe "password encryption" do 104 | 105 | before(:each) do 106 | @user = User.create!(@attr) 107 | end 108 | 109 | it "should have an encrypted password attribute" do 110 | @user.should respond_to(:encrypted_password) 111 | end 112 | 113 | it "should set the encrypted password attribute" do 114 | @user.encrypted_password.should_not be_blank 115 | end 116 | 117 | it "should have a salt" do 118 | @user.should respond_to(:salt) 119 | end 120 | 121 | describe "has_password? method" do 122 | 123 | it "should exist" do 124 | @user.should respond_to(:has_password?) 125 | end 126 | 127 | it "should return true if the passwords match" do 128 | @user.has_password?(@attr[:password]).should be_true 129 | end 130 | 131 | it "should return false if the passwords don't match" do 132 | @user.has_password?("invalid").should be_false 133 | end 134 | end 135 | 136 | describe "authenticate method" do 137 | 138 | it "should exist" do 139 | User.should respond_to(:authenticate) 140 | end 141 | 142 | it "should return nil on email/password mismatch" do 143 | User.authenticate(@attr[:email], "wrongpass").should be_nil 144 | end 145 | 146 | it "should return nil for an email address with no user" do 147 | User.authenticate("bar@foo.com", @attr[:password]).should be_nil 148 | end 149 | 150 | it "should return the user on email/password match" do 151 | User.authenticate(@attr[:email], @attr[:password]).should == @user 152 | end 153 | end 154 | end 155 | 156 | describe "admin attribute" do 157 | 158 | before(:each) do 159 | @user = User.create!(@attr) 160 | end 161 | 162 | it "should respond to admin" do 163 | @user.should respond_to(:admin) 164 | end 165 | 166 | it "should not be an admin by default" do 167 | @user.should_not be_admin 168 | end 169 | 170 | it "should be convertible to an admin" do 171 | @user.toggle!(:admin) 172 | @user.should be_admin 173 | end 174 | end 175 | 176 | describe "micropost associations" do 177 | 178 | before(:each) do 179 | @user = User.create(@attr) 180 | @mp1 = Factory(:micropost, :user => @user, :created_at => 1.day.ago) 181 | @mp2 = Factory(:micropost, :user => @user, :created_at => 1.hour.ago) 182 | end 183 | 184 | it "should have a microposts attribute" do 185 | @user.should respond_to(:microposts) 186 | end 187 | 188 | it "should have the right microposts in the right order" do 189 | @user.microposts.should == [@mp2, @mp1] 190 | end 191 | 192 | it "should destroy associated microposts" do 193 | @user.destroy 194 | [@mp1, @mp2].each do |micropost| 195 | lambda do 196 | Micropost.find(micropost) 197 | end.should raise_error(ActiveRecord::RecordNotFound) 198 | end 199 | end 200 | 201 | describe "status feed" do 202 | it "should have a feed" do 203 | @user.should respond_to(:feed) 204 | end 205 | 206 | it "should include the user's microposts" do 207 | @user.feed.should include(@mp1) 208 | @user.feed.should include(@mp2) 209 | end 210 | 211 | it "should not include a different user's microposts" do 212 | mp3 = Factory(:micropost, 213 | :user => Factory(:user, :email => Factory.next(:email))) 214 | @user.feed.should_not include(mp3) 215 | end 216 | 217 | it "should include the microposts of followed users" do 218 | followed = Factory(:user, :email => Factory.next(:email)) 219 | mp3 = Factory(:micropost, :user => followed) 220 | @user.follow!(followed) 221 | @user.feed.should include(mp3) 222 | end 223 | end 224 | end 225 | 226 | describe "relationships" do 227 | 228 | before(:each) do 229 | @user = User.create!(@attr) 230 | @followed = Factory(:user) 231 | end 232 | 233 | it "should have a relationships method" do 234 | @user.should respond_to(:relationships) 235 | end 236 | 237 | it "should have a following method" do 238 | @user.should respond_to(:following) 239 | end 240 | 241 | it "should follow another user" do 242 | @user.follow!(@followed) 243 | @user.should be_following(@followed) 244 | end 245 | 246 | it "should include the followed user in the following array" do 247 | @user.follow!(@followed) 248 | @user.following.should include(@followed) 249 | end 250 | 251 | it "should have an unfollow! method" do 252 | @user.should respond_to(:unfollow!) 253 | end 254 | 255 | it "should unfollow a user" do 256 | @user.follow!(@followed) 257 | @user.unfollow!(@followed) 258 | @user.should_not be_following(@followed) 259 | end 260 | 261 | it "should have a reverse_relationships method" do 262 | @user.should respond_to(:reverse_relationships) 263 | end 264 | 265 | it "should have a followers method" do 266 | @user.should respond_to(:followers) 267 | end 268 | 269 | it "should include the follower in the followers array" do 270 | @user.follow!(@followed) 271 | @followed.followers.should include(@user) 272 | end 273 | end 274 | end 275 | -------------------------------------------------------------------------------- /spec/requests/friendly_forwardings_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "FriendlyForwardings" do 4 | 5 | it "should forward to the requested page after signin" do 6 | user = Factory(:user) 7 | visit edit_user_path(user) 8 | fill_in :email, :with => user.email 9 | fill_in :password, :with => user.password 10 | click_button 11 | response.should render_template('users/edit') 12 | visit signout_path 13 | visit signin_path 14 | fill_in :email, :with => user.email 15 | fill_in :password, :with => user.password 16 | click_button 17 | response.should render_template('users/show') 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/requests/layout_links_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "LayoutLinks" do 4 | 5 | it "should have a Home page at '/'" do 6 | get '/' 7 | response.should have_selector('title', :content => "Home") 8 | end 9 | 10 | it "should have a Contact page at '/contact'" do 11 | get '/contact' 12 | response.should have_selector('title', :content => "Contact") 13 | end 14 | 15 | it "should have an About page at '/about'" do 16 | get '/about' 17 | response.should have_selector('title', :content => "About") 18 | end 19 | 20 | it "should have a Help page at '/help'" do 21 | get '/help' 22 | response.should have_selector('title', :content => "Help") 23 | end 24 | 25 | it "should have a signup page at '/signup'" do 26 | get '/signup' 27 | response.should have_selector('title', :content => "Sign up") 28 | end 29 | 30 | it "should have a signin page at '/signin'" do 31 | get '/signin' 32 | response.should have_selector('title', :content => "Sign in") 33 | end 34 | 35 | it "should have the right links on the layout" do 36 | visit root_path 37 | response.should have_selector('title', :content => "Home") 38 | click_link "About" 39 | response.should have_selector('title', :content => "About") 40 | click_link "Contact" 41 | response.should have_selector('title', :content => "Contact") 42 | click_link "Home" 43 | response.should have_selector('title', :content => "Home") 44 | click_link "Sign up now!" 45 | response.should have_selector('title', :content => "Sign up") 46 | response.should have_selector('a[href="/"]>img') 47 | end 48 | 49 | describe "when not signed in" do 50 | it "should have a signin link" do 51 | visit root_path 52 | response.should have_selector("a", :href => signin_path, 53 | :content => "Sign in") 54 | end 55 | end 56 | 57 | describe "when signed in" do 58 | 59 | before(:each) do 60 | @user = Factory(:user) 61 | visit signin_path 62 | fill_in :email, :with => @user.email 63 | fill_in :password, :with => @user.password 64 | click_button 65 | end 66 | 67 | it "should have a signout link" do 68 | visit root_path 69 | response.should have_selector("a", :href => signout_path, 70 | :content => "Sign out") 71 | end 72 | 73 | it "should have a profile link" do 74 | visit root_path 75 | response.should have_selector("a", :href => user_path(@user), 76 | :content => "Profile") 77 | end 78 | 79 | it "should have a settings link" do 80 | visit root_path 81 | response.should have_selector("a", :href => edit_user_path(@user), 82 | :content => "Settings") 83 | end 84 | 85 | it "should have a users link" do 86 | visit root_path 87 | response.should have_selector("a", :href => users_path, 88 | :content => "Users") 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /spec/requests/microposts_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Microposts" do 4 | 5 | before(:each) do 6 | user = Factory(:user) 7 | visit signin_path 8 | fill_in :email, :with => user.email 9 | fill_in :password, :with => user.password 10 | click_button 11 | end 12 | 13 | describe "creation" do 14 | 15 | describe "failure" do 16 | it "should not make a new micropost" do 17 | lambda do 18 | visit root_path 19 | fill_in :micropost_content, :with => "" 20 | click_button 21 | response.should render_template('pages/home') 22 | response.should have_selector('div#error_explanation') 23 | end.should_not change(Micropost, :count) 24 | end 25 | end 26 | 27 | describe "success" do 28 | it "should make a new micropost" do 29 | content = "Lorem ipsum dolor sit amet" 30 | lambda do 31 | visit root_path 32 | fill_in :micropost_content, :with => content 33 | click_button 34 | response.should have_selector('span.content', :content => content) 35 | end.should change(Micropost, :count).by(1) 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/requests/users_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Users" do 4 | 5 | describe "signup" do 6 | 7 | describe "failure" do 8 | it "should not make a new user" do 9 | lambda do 10 | visit signup_path 11 | fill_in "Name", :with => "" 12 | fill_in "Email", :with => "" 13 | fill_in "Password", :with => "" 14 | fill_in "Confirmation", :with => "" 15 | click_button 16 | response.should render_template('users/new') 17 | response.should have_selector('div#error_explanation') 18 | end.should_not change(User, :count) 19 | end 20 | end 21 | 22 | describe "success" do 23 | it "should make a new user" do 24 | lambda do 25 | visit signup_path 26 | fill_in "Name", :with => "Example User" 27 | fill_in "Email", :with => "user@example.com" 28 | fill_in "Password", :with => "foobar" 29 | fill_in "Confirmation", :with => "foobar" 30 | click_button 31 | response.should have_selector('div.flash.success', 32 | :content => "Welcome") 33 | response.should render_template('users/show') 34 | end.should change(User, :count).by(1) 35 | end 36 | end 37 | end 38 | 39 | describe "signin" do 40 | 41 | describe "failure" do 42 | it "should not sign a user in" do 43 | visit signin_path 44 | fill_in "Email", :with => "" 45 | fill_in "Password", :with => "" 46 | click_button 47 | response.should have_selector('div.flash.error', 48 | :content => "Invalid") 49 | response.should render_template('sessions/new') 50 | end 51 | end 52 | 53 | describe "success" do 54 | it "should sign a user in and out" do 55 | user = Factory(:user) 56 | visit signin_path 57 | fill_in "Email", :with => user.email 58 | fill_in "Password", :with => user.password 59 | click_button 60 | controller.should be_signed_in 61 | click_link "Sign out" 62 | controller.should_not be_signed_in 63 | end 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'spork' 2 | 3 | Spork.prefork do 4 | # Loading more in this block will cause your tests to run faster. However, 5 | # if you change any configuration or code from libraries loaded here, you'll 6 | # need to restart spork for it take effect. 7 | ENV["RAILS_ENV"] ||= 'test' 8 | require File.expand_path("../../config/environment", __FILE__) 9 | require 'rspec/rails' 10 | 11 | # Requires supporting files with custom matchers and macros, etc, 12 | # in ./support/ and its subdirectories. 13 | Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} 14 | 15 | RSpec.configure do |config| 16 | # == Mock Framework 17 | # 18 | # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: 19 | # 20 | # config.mock_with :mocha 21 | # config.mock_with :flexmock 22 | # config.mock_with :rr 23 | config.mock_with :rspec 24 | 25 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 26 | 27 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 28 | # examples within a transaction, comment the following line or assign false 29 | # instead of true. 30 | config.use_transactional_fixtures = true 31 | 32 | def test_sign_in(user) 33 | controller.sign_in(user) 34 | end 35 | end 36 | end 37 | 38 | Spork.each_run do 39 | end 40 | -------------------------------------------------------------------------------- /vendor/plugins/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/railstutorial/sample_app/fe776b59458d3306cdeaabf49f8232971acc7e1b/vendor/plugins/.gitkeep --------------------------------------------------------------------------------