├── log
└── .keep
├── app
├── mailers
│ ├── .keep
│ ├── application_mailer.rb
│ └── user_mailer.rb
├── models
│ ├── .keep
│ ├── concerns
│ │ └── .keep
│ ├── relationship.rb
│ ├── micropost.rb
│ └── user.rb
├── assets
│ ├── images
│ │ ├── .keep
│ │ └── rails.png
│ ├── stylesheets
│ │ ├── users.scss
│ │ ├── sessions.scss
│ │ ├── microposts.scss
│ │ ├── relationships.scss
│ │ ├── static_pages.scss
│ │ ├── password_resets.scss
│ │ ├── acount_activations.scss
│ │ ├── application.css
│ │ └── custom.css.scss
│ └── javascripts
│ │ ├── users.coffee
│ │ ├── microposts.coffee
│ │ ├── sessions.coffee
│ │ ├── password_resets.coffee
│ │ ├── relationships.coffee
│ │ ├── static_pages.coffee
│ │ ├── acount_activations.coffee
│ │ └── application.js
├── controllers
│ ├── concerns
│ │ └── .keep
│ ├── static_pages_controller.rb
│ ├── application_controller.rb
│ ├── account_activations_controller.rb
│ ├── relationships_controller.rb
│ ├── sessions_controller.rb
│ ├── microposts_controller.rb
│ ├── password_resets_controller.rb
│ └── users_controller.rb
├── views
│ ├── layouts
│ │ ├── mailer.text.erb
│ │ ├── mailer.html.erb
│ │ ├── _shim.html.erb
│ │ ├── _footer.html.erb
│ │ ├── application.html.erb
│ │ └── _header.html.erb
│ ├── static_pages
│ │ ├── home.html.erb
│ │ ├── contact.html.erb
│ │ ├── help.html.erb
│ │ ├── about.html.erb
│ │ ├── _anonymous_user.erb
│ │ └── _signed_in.erb
│ ├── relationships
│ │ ├── create.js.erb
│ │ └── destroy.js.erb
│ ├── shared
│ │ ├── _feed.html.erb
│ │ ├── _user_info.html.erb
│ │ ├── _error_messages.html.erb
│ │ ├── _stats.html.erb
│ │ └── _micropost_form.html.erb
│ ├── users
│ │ ├── index.html.erb
│ │ ├── _follow.html.erb
│ │ ├── _unfollow.html.erb
│ │ ├── new.html.erb
│ │ ├── _follow_form.html.erb
│ │ ├── _user.html.erb
│ │ ├── edit.html.erb
│ │ ├── _form.html.erb
│ │ ├── show.html.erb
│ │ └── show_follow.html.erb
│ ├── user_mailer
│ │ ├── account_activation.text.erb
│ │ ├── password_reset.text.erb
│ │ ├── account_activation.html.erb
│ │ └── password_reset.html.erb
│ ├── password_resets
│ │ ├── new.html.erb
│ │ └── edit.html.erb
│ ├── microposts
│ │ └── _micropost.html.erb
│ └── sessions
│ │ └── new.html.erb
├── helpers
│ ├── microposts_helper.rb
│ ├── static_pages_helper.rb
│ ├── password_resets_helper.rb
│ ├── relationships_helper.rb
│ ├── acount_activations_helper.rb
│ ├── application_helper.rb
│ ├── users_helper.rb
│ └── sessions_helper.rb
└── uploaders
│ └── picture_uploader.rb
├── lib
├── assets
│ └── .keep
└── tasks
│ └── .keep
├── public
├── favicon.ico
├── robots.txt
├── 500.html
├── 422.html
└── 404.html
├── test
├── helpers
│ ├── .keep
│ ├── application_helper_test.rb
│ └── sessions_helper_test.rb
├── mailers
│ ├── .keep
│ ├── previews
│ │ └── user_mailer_preview.rb
│ └── user_mailer_test.rb
├── models
│ ├── .keep
│ ├── relationship_test.rb
│ ├── micropost_test.rb
│ └── user_test.rb
├── controllers
│ ├── .keep
│ ├── sessions_controller_test.rb
│ ├── relationships_controller_test.rb
│ ├── static_pages_controller_test.rb
│ ├── microposts_controller_test.rb
│ └── users_controller_test.rb
├── fixtures
│ ├── .keep
│ ├── rails.png
│ ├── relationships.yml
│ ├── users.yml
│ └── microposts.yml
├── integration
│ ├── .keep
│ ├── site_layout_test.rb
│ ├── users_profile_test.rb
│ ├── users_index_test.rb
│ ├── users_login_test.rb
│ ├── microposts_interface_test.rb
│ ├── users_signup_test.rb
│ ├── users_edit_test.rb
│ ├── following_test.rb
│ └── password_resets_test.rb
└── test_helper.rb
├── vendor
└── assets
│ ├── javascripts
│ └── .keep
│ └── stylesheets
│ └── .keep
├── .Procfile
├── spring
└── 50c4ccb1d8f630979e84c03ba14676d1.pid
├── bin
├── bundle
├── rake
├── rails
├── spring
└── setup
├── config
├── boot.rb
├── initializers
│ ├── skip_image_resizing.rb
│ ├── cookies_serializer.rb
│ ├── session_store.rb
│ ├── mime_types.rb
│ ├── filter_parameter_logging.rb
│ ├── carrier_wave.rb
│ ├── backtrace_silencers.rb
│ ├── assets.rb
│ ├── wrap_parameters.rb
│ └── inflections.rb
├── environment.rb
├── puma.rb
├── database.yml
├── locales
│ └── en.yml
├── routes.rb
├── secrets.yml
├── application.rb
└── environments
│ ├── development.rb
│ ├── test.rb
│ └── production.rb
├── config.ru
├── db
├── migrate
│ ├── 20160225061655_add_admin_to_users.rb
│ ├── 20160224011359_add_index_to_users_email.rb
│ ├── 20160229053312_add_picture_to_microposts.rb
│ ├── 20160224012956_add_password_digest_to_users.rb
│ ├── 20160225004732_add_remember_digest_to_users.rb
│ ├── 20160226104214_add_reset_to_users.rb
│ ├── 20160223235829_create_users.rb
│ ├── 20160225093821_add_activation_to_users.rb
│ ├── 20160227022814_create_microposts.rb
│ └── 20160301020419_create_relationships.rb
├── seeds.rb
└── schema.rb
├── README.md
├── Rakefile
├── .gitignore
├── Gemfile
├── Guardfile
└── Gemfile.lock
/log/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/mailers/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/models/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/helpers/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/mailers/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/models/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/assets/images/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/controllers/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/fixtures/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/integration/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.Procfile:
--------------------------------------------------------------------------------
1 | web: bundle exec puma -C config/puma.rb
2 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.text.erb:
--------------------------------------------------------------------------------
1 | <%= yield %>
2 |
--------------------------------------------------------------------------------
/spring/50c4ccb1d8f630979e84c03ba14676d1.pid:
--------------------------------------------------------------------------------
1 | 3425
2 |
--------------------------------------------------------------------------------
/app/helpers/microposts_helper.rb:
--------------------------------------------------------------------------------
1 | module MicropostsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/static_pages_helper.rb:
--------------------------------------------------------------------------------
1 | module StaticPagesHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/password_resets_helper.rb:
--------------------------------------------------------------------------------
1 | module PasswordResetsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/relationships_helper.rb:
--------------------------------------------------------------------------------
1 | module RelationshipsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/acount_activations_helper.rb:
--------------------------------------------------------------------------------
1 | module AcountActivationsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= yield %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/fixtures/rails.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainStack/sample-app/master/test/fixtures/rails.png
--------------------------------------------------------------------------------
/app/assets/images/rails.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainStack/sample-app/master/app/assets/images/rails.png
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: "noreply@example.com"
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 |
--------------------------------------------------------------------------------
/app/views/layouts/_shim.html.erb:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/config/initializers/skip_image_resizing.rb:
--------------------------------------------------------------------------------
1 | if Rails.env.test?
2 | CarrierWave.configure do |config|
3 | config.enable_processing = false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/views/static_pages/home.html.erb:
--------------------------------------------------------------------------------
1 | <% if logged_in? %>
2 | <%= render 'static_pages/signed_in' %>
3 | <% else %>
4 | <%= render 'anonymous_user' %>
5 | <% end %>
6 |
--------------------------------------------------------------------------------
/app/views/relationships/create.js.erb:
--------------------------------------------------------------------------------
1 | $("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");
2 | $("#followers").html('<%= @user.followers.count %>');
3 |
--------------------------------------------------------------------------------
/app/views/relationships/destroy.js.erb:
--------------------------------------------------------------------------------
1 | $("#follow_form").html("<%= escape_javascript(render('users/follow')) %>");
2 | $("#followers").html('<%= @user.followers.count %>');
3 |
--------------------------------------------------------------------------------
/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 Rails.application
5 |
--------------------------------------------------------------------------------
/db/migrate/20160225061655_add_admin_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddAdminToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :admin, :boolean
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.action_dispatch.cookies_serializer = :json
4 |
--------------------------------------------------------------------------------
/app/views/shared/_feed.html.erb:
--------------------------------------------------------------------------------
1 | <% if @feed_items.any? %>
2 |
3 | <%= render @feed_items %>
4 |
5 | <%= will_paginate @feed_items %>
6 | <% end %>
7 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.session_store :cookie_store, key: '_sample_app_session'
4 |
--------------------------------------------------------------------------------
/db/migrate/20160224011359_add_index_to_users_email.rb:
--------------------------------------------------------------------------------
1 | class AddIndexToUsersEmail < ActiveRecord::Migration
2 | def change
3 | add_index :users, :email, unique: true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160229053312_add_picture_to_microposts.rb:
--------------------------------------------------------------------------------
1 | class AddPictureToMicroposts < ActiveRecord::Migration
2 | def change
3 | add_column :microposts, :picture, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/db/migrate/20160224012956_add_password_digest_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddPasswordDigestToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :password_digest, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20160225004732_add_remember_digest_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddRememberDigestToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :remember_digest, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/users.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Users controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/sessions.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Sessions controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/views/users/index.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, 'All users') %>
2 | All users
3 |
4 | <%= will_paginate %>
5 |
6 |
7 | <%= render @users %>
8 |
9 |
10 | <%= will_paginate %>
11 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/microposts.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Microposts controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/relationships.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Relationships controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/static_pages.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the StaticPages controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/db/migrate/20160226104214_add_reset_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddResetToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :reset_digest, :string
4 | add_column :users, :reset_sent_at, :datetime
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/password_resets.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the PasswordResets controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.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 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/acount_activations.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the AcountActivations controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/views/user_mailer/account_activation.text.erb:
--------------------------------------------------------------------------------
1 | Hi <%= @user.name %>,
2 |
3 | Welcome to the Sample App! Click on the link below to activate your account:
4 |
5 | <%= edit_account_activation_url(@user.activation_token, email: @user.email) %>
6 |
--------------------------------------------------------------------------------
/app/views/users/_follow.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
2 | <%= hidden_field_tag :followed_id, @user.id %>
3 | <%= f.submit "Follow", class: "btn btn-primary" %>
4 | <% end %>
5 |
--------------------------------------------------------------------------------
/test/controllers/sessions_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SessionsControllerTest < ActionController::TestCase
4 | test "should get new" do
5 | get :new
6 | assert_response :success
7 | end
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ruby on Rails Tutorial: sample application
2 |
3 | This is the sample application for the
4 | [*Ruby on Rails Tutorial:
5 | Learn Web Development with Rails*](http://www.railstutorial.org/)
6 | by [Michael Hartl](http://www.michaelhartl.com/).
--------------------------------------------------------------------------------
/app/assets/javascripts/users.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/views/static_pages/contact.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, "Contact") %>
2 | Contact
3 |
4 | Contact the Ruby on Rails Tutorial about the sample app at the
5 | contact page .
6 |
7 |
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/app/assets/javascripts/microposts.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/sessions.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/models/relationship.rb:
--------------------------------------------------------------------------------
1 | class Relationship < ActiveRecord::Base
2 | belongs_to :follower, class_name: "User"
3 | belongs_to :followed, class_name: "User"
4 | validates :follower_id, presence: true
5 | validates :followed_id, presence: true
6 | end
7 |
--------------------------------------------------------------------------------
/app/views/users/_unfollow.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(current_user.active_relationships.find_by(followed_id: @user.id),
2 | html: { method: :delete },
3 | remote: true) do |f| %>
4 | <%= f.submit "Unfollow", class: "btn" %>
5 | <% end %>
6 |
--------------------------------------------------------------------------------
/app/views/users/new.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, 'Sign up') %>
2 | <% provide(:button_text, 'Create my account') %>
3 | Sign up
4 |
5 |
6 | <%= render 'form' %>
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/assets/javascripts/password_resets.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/relationships.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/static_pages.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | require_relative '../config/boot'
8 | require 'rake'
9 | Rake.application.run
10 |
--------------------------------------------------------------------------------
/app/assets/javascripts/acount_activations.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/db/migrate/20160223235829_create_users.rb:
--------------------------------------------------------------------------------
1 | class CreateUsers < ActiveRecord::Migration
2 | def change
3 | create_table :users do |t|
4 | t.string :name
5 | t.string :email
6 |
7 | t.timestamps null: false
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/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 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/app/views/shared/_user_info.html.erb:
--------------------------------------------------------------------------------
1 | <%= link_to gravatar_for(current_user, size: 50), current_user %>
2 | <%= current_user.name %>
3 | <%= link_to "view my profile", current_user %>
4 | <%= pluralize(current_user.microposts.count, "micropost") %>
5 |
--------------------------------------------------------------------------------
/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 %>
10 |
--------------------------------------------------------------------------------
/test/fixtures/relationships.yml:
--------------------------------------------------------------------------------
1 | one:
2 | follower: michael
3 | followed: lana
4 |
5 | two:
6 | follower: michael
7 | followed: malory
8 |
9 | three:
10 | follower: lana
11 | followed: michael
12 |
13 | four:
14 | follower: archer
15 | followed: michael
16 |
--------------------------------------------------------------------------------
/app/views/users/_user.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= gravatar_for user, size: 50 %>
3 | <%= link_to user.name, user %>
4 | <% if current_user.admin? && !current_user?(user) %>
5 | | <%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %>
6 | <% end %>
7 |
8 |
--------------------------------------------------------------------------------
/db/migrate/20160225093821_add_activation_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddActivationToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :activation_digest, :string
4 | add_column :users, :activated, :boolean, default: false
5 | add_column :users, :activated_at, :datetime
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | APP_PATH = File.expand_path('../../config/application', __FILE__)
8 | require_relative '../config/boot'
9 | require 'rails/commands'
10 |
--------------------------------------------------------------------------------
/test/helpers/application_helper_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class ApplicationHelperTest < ActionView::TestCase
4 | test "full title helper" do
5 | assert_equal full_title, "Ruby on Rails Tutorial Sample App"
6 | assert_equal full_title("Help"), "Help | Ruby on Rails Tutorial Sample App"
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/app/mailers/user_mailer.rb:
--------------------------------------------------------------------------------
1 | class UserMailer < ApplicationMailer
2 |
3 | def account_activation(user)
4 | @user = user
5 | mail to: user.email, subject: "Account activation"
6 | end
7 |
8 | def password_reset(user)
9 | @user = user
10 | mail to: user.email, subject: "Password reset"
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/views/user_mailer/password_reset.text.erb:
--------------------------------------------------------------------------------
1 | To reset your password click the link below:
2 |
3 | <%= edit_password_reset_url(@user.reset_token, email: @user.email) %>
4 |
5 | This link will expire in two hours.
6 |
7 | If you did not request your password to be reset, please ignore this email and
8 | your password will stay as it is.
9 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 |
3 | # Returns the full title on a per-page basis.
4 | def full_title(page_title = '')
5 | base_title = "Ruby on Rails Tutorial Sample App"
6 | if page_title.empty?
7 | base_title
8 | else
9 | page_title + " | " + base_title
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/helpers/users_helper.rb:
--------------------------------------------------------------------------------
1 | module UsersHelper
2 | def gravatar_for(user, options = { size: 80 })
3 | gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
4 | size = options[:size]
5 | gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
6 | image_tag(gravatar_url, alt: user.name, class: "gravatar")
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20160227022814_create_microposts.rb:
--------------------------------------------------------------------------------
1 | class CreateMicroposts < ActiveRecord::Migration
2 | def change
3 | create_table :microposts do |t|
4 | t.text :content
5 | t.references :user, index: true, foreign_key: true
6 |
7 | t.timestamps null: false
8 | end
9 | add_index :microposts, [:user_id, :created_at]
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/app/views/user_mailer/account_activation.html.erb:
--------------------------------------------------------------------------------
1 | Sample App
2 |
3 | Hi <%= @user.name %>,
4 |
5 |
6 | Welcome to the Sample App! Click on the link below to activate your account:
7 |
8 |
9 | <%= link_to "Activate", edit_account_activation_url(@user.activation_token,
10 | email: @user.email) %>
11 |
--------------------------------------------------------------------------------
/app/views/static_pages/help.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, "Help") %>
2 | Help
3 |
4 | Get help on the Ruby on Rails Tutorial at the
5 | Rails Tutorial help section .
6 | To get help on this sample app, see the
7 | Ruby on Rails Tutorial
8 | book .
9 |
10 |
--------------------------------------------------------------------------------
/app/controllers/static_pages_controller.rb:
--------------------------------------------------------------------------------
1 | class StaticPagesController < ApplicationController
2 | def home
3 | if logged_in?
4 | @micropost = current_user.microposts.build
5 | @feed_items = current_user.feed.paginate(page: params[:page])
6 | end
7 | end
8 |
9 | def help
10 | end
11 |
12 | def about
13 | end
14 |
15 | def contact
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/app/views/shared/_error_messages.html.erb:
--------------------------------------------------------------------------------
1 | <% if object.errors.any? %>
2 |
3 |
4 | The form contains <%= pluralize(object.errors.count, "error") %>.
5 |
6 |
7 | <% object.errors.full_messages.each do |msg| %>
8 | <%= msg %>
9 | <% end %>
10 |
11 |
12 | <% end %>
13 |
--------------------------------------------------------------------------------
/config/initializers/carrier_wave.rb:
--------------------------------------------------------------------------------
1 | if Rails.env.production?
2 | CarrierWave.configure do |config|
3 | config.fog_credentials = {
4 | # Configuration for Amazon S3
5 | :provider => 'AWS',
6 | :aws_access_key_id => ENV['S3_ACCESS_KEY'],
7 | :aws_secret_access_key => ENV['S3_SECRET_KEY']
8 | }
9 | config.fog_directory = ENV['S3_BUCKET']
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/app/views/users/edit.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, 'Edit user') %>
2 | <% provide(:button_text, 'Save changes') %>
3 | Update your profile
4 |
5 |
6 | <%= render 'form' %>
7 |
8 | <%= gravatar_for @user %>
9 |
Change
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | protect_from_forgery with: :exception
3 | include SessionsHelper
4 |
5 | private
6 |
7 | # Confirms a logged-in user.
8 | def logged_in_user
9 | unless logged_in?
10 | store_location
11 | flash[:danger] = "Please log in."
12 | redirect_to login_url
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/views/password_resets/new.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, "Forgot password") %>
2 | Forgot password
3 |
4 |
5 |
6 | <%= form_for(:password_reset, url: password_resets_path) do |f| %>
7 | <%= f.label :email %>
8 | <%= f.email_field :email, class: 'form-control' %>
9 |
10 | <%= f.submit "Submit", class: "btn btn-primary" %>
11 | <% end %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/views/shared/_stats.html.erb:
--------------------------------------------------------------------------------
1 | <% @user ||= current_user %>
2 |
16 |
--------------------------------------------------------------------------------
/db/migrate/20160301020419_create_relationships.rb:
--------------------------------------------------------------------------------
1 | class CreateRelationships < ActiveRecord::Migration
2 | def change
3 | create_table :relationships do |t|
4 | t.integer :follower_id
5 | t.integer :followed_id
6 |
7 | t.timestamps null: false
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 | end
14 |
--------------------------------------------------------------------------------
/app/views/layouts/_footer.html.erb:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/app/views/static_pages/about.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, "About") %>
2 | About
3 |
4 | The Ruby on Rails
5 | Tutorial is a
6 | book and
7 | screencast series
8 | to teach web development with
9 | Ruby on Rails .
10 | This is the sample application for the tutorial.
11 |
12 |
--------------------------------------------------------------------------------
/app/views/user_mailer/password_reset.html.erb:
--------------------------------------------------------------------------------
1 | Password reset
2 |
3 | To reset your password click the link below:
4 |
5 | <%= link_to "Reset password", edit_password_reset_url(@user.reset_token,
6 | email: @user.email) %>
7 |
8 | This link will expire in two hours.
9 |
10 |
11 | If you did not request your password to be reset, please ignore this email and
12 | your password will stay as it is.
13 |
14 |
--------------------------------------------------------------------------------
/app/views/static_pages/_anonymous_user.erb:
--------------------------------------------------------------------------------
1 |
2 |
Welcome to the Sample App
3 |
4 |
5 | This is the home page for the
6 | Ruby on Rails Tutorial
7 | sample application.
8 |
9 |
10 | <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
11 |
12 |
13 | <%= link_to image_tag("rails.png", alt: "Rails logo"),
14 | 'http://rubyonrails.org/' %>
15 |
--------------------------------------------------------------------------------
/app/views/static_pages/_signed_in.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= render 'shared/user_info' %>
5 |
6 |
7 | <%= render 'shared/stats' %>
8 |
9 |
10 | <%= render 'shared/micropost_form' %>
11 |
12 |
13 |
14 |
Micropost Feed
15 | <%= render 'shared/feed' %>
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/controllers/account_activations_controller.rb:
--------------------------------------------------------------------------------
1 | class AccountActivationsController < ApplicationController
2 |
3 | def edit
4 | user = User.find_by(email: params[:email])
5 | if user && !user.activated? && user.authenticated?(:activation, params[:id])
6 | user.activate
7 | log_in user
8 | flash[:success] = "Account activated!"
9 | redirect_to user
10 | else
11 | flash[:danger] = "Invalid activation link"
12 | redirect_to root_url
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/test/integration/site_layout_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SiteLayoutTest < ActionDispatch::IntegrationTest
4 |
5 | test "layout links" do
6 | get root_path
7 | assert_template 'static_pages/home'
8 | assert_select "a[href=?]", root_path, count: 2
9 | assert_select "a[href=?]", help_path
10 | assert_select "a[href=?]", about_path
11 | assert_select "a[href=?]", contact_path
12 | get signup_path
13 | assert_select "title", full_title("Sign up")
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/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 | Rails.backtrace_cleaner.add_silencer { |line| line =~ /rvm/ }
6 |
7 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
8 | # Rails.backtrace_cleaner.remove_silencers!
9 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads spring without using Bundler, in order to be fast.
4 | # It gets overwritten when you run the `spring binstub` command.
5 |
6 | unless defined?(Spring)
7 | require 'rubygems'
8 | require 'bundler'
9 |
10 | if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m))
11 | Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq }
12 | gem 'spring', match[1]
13 | require 'spring/binstub'
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/models/micropost.rb:
--------------------------------------------------------------------------------
1 | class Micropost < ActiveRecord::Base
2 | belongs_to :user
3 | default_scope -> { order(created_at: :desc) }
4 | mount_uploader :picture, PictureUploader
5 | validates :user_id, presence: true
6 | validates :content, presence: true, length: { maximum: 140 }
7 | validate :picture_size
8 |
9 | private
10 |
11 | # Validates the size of an uploaded picture.
12 | def picture_size
13 | if picture.size > 5.megabytes
14 | errors.add(:picture, "should be less than 5MB")
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = '1.0'
5 |
6 | # Add additional assets to the asset load path
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 |
9 | # Precompile additional assets.
10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
11 | # Rails.application.config.assets.precompile += %w( search.js )
12 |
--------------------------------------------------------------------------------
/config/puma.rb:
--------------------------------------------------------------------------------
1 | workers Integer(ENV['WEB_CONCURRENCY'] || 2)
2 | threads_count = Integer(ENV['MAX_THREADS'] || 5)
3 | threads threads_count, threads_count
4 |
5 | preload_app!
6 |
7 | rackup DefaultRackup
8 | port ENV['PORT'] || 3000
9 | environment ENV['RACK_ENV'] || 'development'
10 |
11 | on_worker_boot do
12 | # Worker specific setup for Rails 4.1+
13 | # See: https://devcenter.heroku.com/articles/
14 | # deploying-rails-applications-with-the-puma-web-server#on-worker-boot
15 | ActiveRecord::Base.establish_connection
16 | end
17 |
--------------------------------------------------------------------------------
/test/helpers/sessions_helper_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SessionsHelperTest < ActionView::TestCase
4 |
5 | def setup
6 | @user = users(:michael)
7 | remember(@user)
8 | end
9 |
10 | test "current_user returns right user when session is nil" do
11 | assert_equal @user, current_user
12 | assert is_logged_in?
13 | end
14 |
15 | test "current_user returns nil when remember digest is wrong" do
16 | @user.update_attribute(:remember_digest, User.digest(User.new_token))
17 | assert_nil current_user
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/test/controllers/relationships_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class RelationshipsControllerTest < ActionController::TestCase
4 |
5 | test "create should require logged-in user" do
6 | assert_no_difference 'Relationship.count' do
7 | post :create
8 | end
9 | assert_redirected_to login_url
10 | end
11 |
12 | test "destroy should require logged-in user" do
13 | assert_no_difference 'Relationship.count' do
14 | delete :destroy, id: relationships(:one)
15 | end
16 | assert_redirected_to login_url
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/models/relationship_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class RelationshipTest < ActiveSupport::TestCase
4 |
5 | def setup
6 | @relationship = Relationship.new(follower_id: 1, followed_id: 2)
7 | end
8 |
9 | test "should be valid" do
10 | assert @relationship.valid?
11 | end
12 |
13 | test "should require a follower_id" do
14 | @relationship.follower_id = nil
15 | assert_not @relationship.valid?
16 | end
17 |
18 | test "should require a followed_id" do
19 | @relationship.followed_id = nil
20 | assert_not @relationship.valid?
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/controllers/relationships_controller.rb:
--------------------------------------------------------------------------------
1 | class RelationshipsController < ApplicationController
2 | before_action :logged_in_user
3 |
4 | def create
5 | @user = User.find(params[: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
22 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/app/views/users/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(@user) do |f| %>
2 | <%= render 'shared/error_messages', object: f.object %>
3 |
4 | <%= f.label :name %>
5 | <%= f.text_field :name, class: 'form-control' %>
6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, class: 'form-control' %>
9 |
10 | <%= f.label :password %>
11 | <%= f.password_field :password, class: 'form-control' %>
12 |
13 | <%= f.label :password_confirmation %>
14 | <%= f.password_field :password_confirmation, class: 'form-control' %>
15 |
16 | <%= f.submit yield(:button_text), class: "btn btn-primary" %>
17 | <% end %>
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | /.bundle
9 |
10 | # Ignore the default SQLite database.
11 | /db/*.sqlite3
12 | /db/*.sqlite3-journal
13 |
14 | # Ignore all logfiles and tempfiles.
15 | /log/*
16 | !/log/.keep
17 | /tmp
18 |
19 | # Ignore Spring files.
20 | /spring/*.pid
21 |
22 | # Ignore uploaded test images.
23 | /public/uploads
24 |
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem 'sqlite3'
6 | #
7 | default: &default
8 | adapter: sqlite3
9 | pool: 5
10 | timeout: 5000
11 |
12 | development:
13 | <<: *default
14 | database: db/development.sqlite3
15 |
16 | # Warning: The database defined as "test" will be erased and
17 | # re-generated from your development database when you run "rake".
18 | # Do not set this db to the same as development or production.
19 | test:
20 | <<: *default
21 | database: db/test.sqlite3
22 |
23 | production:
24 | <<: *default
25 | database: db/production.sqlite3
26 |
--------------------------------------------------------------------------------
/test/mailers/previews/user_mailer_preview.rb:
--------------------------------------------------------------------------------
1 | # Preview all emails at http://localhost:3000/rails/mailers/user_mailer
2 | class UserMailerPreview < ActionMailer::Preview
3 |
4 | # Preview this email at http://localhost:3000/rails/mailers/user_mailer/account_activation
5 | def account_activation
6 | user = User.first
7 | user.activation_token = User.new_token
8 | UserMailer.account_activation(user)
9 | end
10 |
11 | # Preview this email at http://localhost:3000/rails/mailers/user_mailer/password_reset
12 | def password_reset
13 | user = User.first
14 | user.reset_token = User.new_token
15 | UserMailer.password_reset(user)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/test/mailers/user_mailer_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UserMailerTest < ActionMailer::TestCase
4 |
5 | test "account_activation" do
6 | user = users(:michael)
7 | user.reset_token = User.new_token
8 | user.activation_token = User.new_token
9 | mail = UserMailer.account_activation(user)
10 | assert_equal "Account activation", mail.subject
11 | assert_equal [user.email], mail.to
12 | assert_equal ["noreply@example.com"], mail.from
13 | assert_match user.name, mail.body.encoded
14 | assert_match user.activation_token, mail.body.encoded
15 | assert_match CGI::escape(user.email), mail.body.encoded
16 | end
17 | end
--------------------------------------------------------------------------------
/app/uploaders/picture_uploader.rb:
--------------------------------------------------------------------------------
1 | class PictureUploader < CarrierWave::Uploader::Base
2 | include CarrierWave::MiniMagick
3 | process resize_to_limit: [400, 400]
4 |
5 | if Rails.env.production?
6 | storage :fog
7 | else
8 | storage :file
9 | end
10 |
11 | # Override the directory where uploaded files will be stored.
12 | # This is a sensible default for uploaders that are meant to be mounted:
13 | def store_dir
14 | "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
15 | end
16 |
17 | # Add a white list of extensions which are allowed to be uploaded.
18 | def extension_white_list
19 | %w(jpg jpeg gif png)
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/app/views/microposts/_micropost.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
3 | <%= link_to micropost.user.name, micropost.user %>
4 |
5 | <%= micropost.content %>
6 | <%= image_tag micropost.picture.url if micropost.picture? %>
7 |
8 |
9 | Posted <%= time_ago_in_words(micropost.created_at) %> ago.
10 | <% if current_user?(micropost.user) %>
11 | <%= link_to "delete", micropost, method: :delete,
12 | data: { confirm: "You sure?" } %>
13 | <% end %>
14 |
15 |
16 |
--------------------------------------------------------------------------------
/test/integration/users_profile_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersProfileTest < ActionDispatch::IntegrationTest
4 | include ApplicationHelper
5 |
6 | def setup
7 | @user = users(:michael)
8 | end
9 |
10 | test "profile display" do
11 | get user_path(@user)
12 | assert_template 'users/show'
13 | assert_select 'title', full_title(@user.name)
14 | assert_select 'h1', text: @user.name
15 | assert_select 'h1>img.gravatar'
16 | assert_match @user.microposts.count.to_s, response.body
17 | assert_select 'div.pagination'
18 | @user.microposts.paginate(page: 1).each do |micropost|
19 | assert_match micropost.content, response.body
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/views/users/show.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, @user.name) %>
2 |
3 |
4 |
5 |
6 | <%= gravatar_for @user %>
7 | <%= @user.name %>
8 |
9 |
10 |
11 | <%= render 'shared/stats' %>
12 |
13 |
14 |
15 | <%= render 'follow_form' if logged_in? %>
16 | <% if @user.microposts.any? %>
17 |
Microposts (<%= @user.microposts.count %>)
18 |
19 | <%= render @microposts %>
20 |
21 | <%= will_paginate @microposts %>
22 | <% end %>
23 |
24 |
--------------------------------------------------------------------------------
/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. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # To learn more, please read the Rails Internationalization guide
20 | # available at http://guides.rubyonrails.org/i18n.html.
21 |
22 | en:
23 | hello: "Hello world"
24 |
--------------------------------------------------------------------------------
/app/views/password_resets/edit.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, 'Reset password') %>
2 | Reset password
3 |
4 |
5 |
6 | <%= form_for(@user, url: password_reset_path(params[:id])) do |f| %>
7 | <%= render 'shared/error_messages', object: f.object %>
8 |
9 | <%= hidden_field_tag :email, @user.email %>
10 |
11 | <%= f.label :password %>
12 | <%= f.password_field :password, class: 'form-control' %>
13 |
14 | <%= f.label :password_confirmation, "Confirmation" %>
15 | <%= f.password_field :password_confirmation, class: 'form-control' %>
16 |
17 | <%= f.submit "Update password", class: "btn btn-primary" %>
18 | <% end %>
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // compiled file.
9 | //
10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require jquery
14 | //= require jquery_ujs
15 | //= require bootstrap
16 | //= require turbolinks
17 | //= require_tree .
18 |
--------------------------------------------------------------------------------
/app/views/shared/_micropost_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(@micropost, html: { multipart: true }) do |f| %>
2 | <%= render 'shared/error_messages', object: f.object %>
3 |
4 | <%= f.text_area :content, placeholder: "Compose new micropost..." %>
5 |
6 | <%= f.submit "Post", class: "btn btn-primary" %>
7 |
8 | <%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %>
9 |
10 | <% end %>
11 |
12 |
20 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which
3 | * will include all the files listed below.
4 | *
5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets,
6 | * vendor/assets/stylesheets, or vendor/assets/stylesheets of plugins, if any,
7 | * can be referenced here using a relative path.
8 | *
9 | * You're free to add application-wide styles to this file and they'll appear
10 | * at the bottom of the compiled file so the styles you add here take
11 | * precedence over styles defined in any styles defined in the other CSS/SCSS
12 | * files in this directory. It is generally better to create a new file per
13 | * style scope.
14 | *
15 | *= require_tree .
16 | *= require_self
17 | */
18 |
--------------------------------------------------------------------------------
/test/controllers/static_pages_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class StaticPagesControllerTest < ActionController::TestCase
4 | test "should get home" do
5 | get :home
6 | assert_response :success
7 | assert_select "title", "Ruby on Rails Tutorial Sample App"
8 | end
9 |
10 | test "should get help" do
11 | get :help
12 | assert_response :success
13 | assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
14 | end
15 |
16 | test "should get about" do
17 | get :about
18 | assert_response :success
19 | assert_select "title", "About | Ruby on Rails Tutorial Sample App"
20 | end
21 |
22 | test "should get contact" do
23 | get :contact
24 | assert_response :success
25 | assert_select "title", "Contact | Ruby on Rails Tutorial Sample App"
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= full_title(yield(:title)) %>
5 | <%= stylesheet_link_tag 'application', media: 'all',
6 | 'data-turbolinks-track' => true %>
7 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
8 | <%= csrf_meta_tags %>
9 | <%= render 'layouts/shim' %>
10 |
11 |
12 | <%= render 'layouts/header' %>
13 |
14 | <% flash.each do |message_type, message| %>
15 | <%= content_tag(:div, message, class: "alert alert-#{message_type}") %>
16 | <% end %>
17 | <%= yield %>
18 | <%= render 'layouts/footer' %>
19 | <%= debug(params) if Rails.env.development? %>
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | get 'password_resets/new'
3 |
4 | get 'password_resets/edit'
5 |
6 | root 'static_pages#home'
7 | get 'help' => 'static_pages#help'
8 | get 'about' => 'static_pages#about'
9 | get 'contact' => 'static_pages#contact'
10 | get 'signup' => 'users#new'
11 | get 'login' => 'sessions#new'
12 | post 'login' => 'sessions#create'
13 | delete 'logout' => 'sessions#destroy'
14 | resources :users do
15 | member do
16 | get :following, :followers
17 | end
18 | end
19 | resources :users
20 | resources :account_activations, only: [:edit]
21 | resources :password_resets, only: [:new, :create, :edit, :update]
22 | resources :microposts, only: [:create, :destroy]
23 | resources :relationships, only: [:create, :destroy]
24 | end
25 |
--------------------------------------------------------------------------------
/app/views/sessions/new.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, "Log in") %>
2 | Log in
3 |
4 |
5 |
6 | <%= form_for(:session, url: login_path) do |f| %>
7 |
8 | <%= f.label :email %>
9 | <%= f.email_field :email, class: 'form-control' %>
10 |
11 | <%= f.label :password %>
12 | <%= link_to "(forgot password)", new_password_reset_path %>
13 | <%= f.password_field :password, class: 'form-control' %>
14 |
15 | <%= f.label :remember_me, class: "checkbox inline" do %>
16 | <%= f.check_box :remember_me %>
17 |
Remember me on this computer
18 | <% end %>
19 |
20 | <%= f.submit "Log in", class: "btn btn-primary" %>
21 | <% end %>
22 |
23 |
New user? <%= link_to "Sign up now!", signup_path %>
24 |
25 |
--------------------------------------------------------------------------------
/app/controllers/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | class SessionsController < ApplicationController
2 |
3 | def new
4 | end
5 |
6 | def create
7 | @user = User.find_by(email: params[:session][:email].downcase)
8 | if @user && @user.authenticate(params[:session][:password])
9 | if @user.activated?
10 | log_in @user
11 | params[:session][:remember_me] == '1' ? remember(@user) : forget(@user)
12 | redirect_back_or @user
13 | else
14 | message = "Account not activated. "
15 | message += "Check your email for the activation link."
16 | flash[:warning] = message
17 | redirect_to root_url
18 | end
19 | else
20 | flash.now[:danger] = 'Invalid email/password combination'
21 | render 'new'
22 | end
23 | end
24 |
25 | def destroy
26 | log_out if logged_in?
27 | redirect_to root_url
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 |
4 | # path to your application root.
5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6 |
7 | Dir.chdir APP_ROOT do
8 | # This script is a starting point to setup your application.
9 | # Add necessary setup steps to this file:
10 |
11 | puts "== Installing dependencies =="
12 | system "gem install bundler --conservative"
13 | system "bundle check || bundle install"
14 |
15 | # puts "\n== Copying sample files =="
16 | # unless File.exist?("config/database.yml")
17 | # system "cp config/database.yml.sample config/database.yml"
18 | # end
19 |
20 | puts "\n== Preparing database =="
21 | system "bin/rake db:setup"
22 |
23 | puts "\n== Removing old logs and tempfiles =="
24 | system "rm -f log/*"
25 | system "rm -rf tmp/cache"
26 |
27 | puts "\n== Restarting application server =="
28 | system "touch tmp/restart.txt"
29 | end
30 |
--------------------------------------------------------------------------------
/test/models/micropost_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class MicropostTest < ActiveSupport::TestCase
4 |
5 | def setup
6 | @user = users(:michael)
7 | # This code is not idiomatically correct.
8 | @micropost = @user.microposts.build(content: "Lorem ipsum")
9 | end
10 |
11 | test "should be valid" do
12 | assert @micropost.valid?
13 | end
14 |
15 | test "user id should be present" do
16 | @micropost.user_id = nil
17 | assert_not @micropost.valid?
18 | end
19 |
20 | test "content should be present" do
21 | @micropost.content = " "
22 | assert_not @micropost.valid?
23 | end
24 |
25 | test "content should be at most 140 characters" do
26 | @micropost.content = "a" * 141
27 | assert_not @micropost.valid?
28 | end
29 |
30 | test "order should be most recent first" do
31 | assert_equal microposts(:most_recent), Micropost.first
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/app/controllers/microposts_controller.rb:
--------------------------------------------------------------------------------
1 | class MicropostsController < ApplicationController
2 | before_action :logged_in_user, only: [:create, :destroy]
3 | before_action :correct_user, only: :destroy
4 |
5 | def create
6 | @micropost = current_user.microposts.build(micropost_params)
7 | if @micropost.save
8 | flash[:success] = "Micropost created!"
9 | redirect_to root_url
10 | else
11 | @feed_items = []
12 | render 'static_pages/home'
13 | end
14 | end
15 |
16 | def destroy
17 | @micropost.destroy
18 | flash[:success] = "Micropost deleted"
19 | redirect_to request.referrer || root_url
20 | end
21 |
22 | private
23 |
24 | def micropost_params
25 | params.require(:micropost).permit(:content, :picture)
26 | end
27 |
28 | def correct_user
29 | @micropost = current_user.microposts.find_by(id: params[:id])
30 | redirect_to root_url if @micropost.nil?
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/test/controllers/microposts_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class MicropostsControllerTest < ActionController::TestCase
4 |
5 | def setup
6 | @micropost = microposts(:orange)
7 | end
8 |
9 | test "should redirect create when not logged in" do
10 | assert_no_difference 'Micropost.count' do
11 | post :create, micropost: { content: "Lorem ipsum" }
12 | end
13 | assert_redirected_to login_url
14 | end
15 |
16 | test "should redirect destroy when not logged in" do
17 | assert_no_difference 'Micropost.count' do
18 | delete :destroy, id: @micropost
19 | end
20 | assert_redirected_to login_url
21 | end
22 |
23 | test "should redirect destroy for wrong micropost" do
24 | log_in_as(users(:michael))
25 | micropost = microposts(:ants)
26 | assert_no_difference 'Micropost.count' do
27 | delete :destroy, id: micropost
28 | end
29 | assert_redirected_to root_url
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/app/views/users/show_follow.html.erb:
--------------------------------------------------------------------------------
1 | <% provide(:title, @title) %>
2 |
3 |
21 |
22 |
<%= @title %>
23 | <% if @users.any? %>
24 |
25 | <%= render @users %>
26 |
27 | <%= will_paginate %>
28 | <% end %>
29 |
30 |
31 |
--------------------------------------------------------------------------------
/test/integration/users_index_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersIndexTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | @admin = users(:michael)
7 | @non_admin = users(:archer)
8 | end
9 |
10 | test "index as admin including pagination and delete links" do
11 | log_in_as(@admin)
12 | get users_path
13 | assert_template 'users/index'
14 | assert_select 'div.pagination'
15 | first_page_of_users = User.paginate(page: 1)
16 | first_page_of_users.each do |user|
17 | assert_select 'a[href=?]', user_path(user), text: user.name
18 | unless user == @admin
19 | assert_select 'a[href=?]', user_path(user), text: 'delete'
20 | end
21 | end
22 | assert_difference 'User.count', -1 do
23 | delete user_path(@non_admin)
24 | end
25 | end
26 |
27 | test "index as non-admin" do
28 | log_in_as(@non_admin)
29 | get users_path
30 | assert_select 'a', text: 'delete', count: 0
31 | end
32 | end
--------------------------------------------------------------------------------
/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rake secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | development:
14 | secret_key_base: bb823ae575348c91fbc5e73e71ee42dc2efa73605a77500fdcd23e381a42c8ed3ee402947c112e9142461c844f8ad3571b4018cd20513117439bbb3df159c938
15 |
16 | test:
17 | secret_key_base: 69a8996cfd4c36002cebdc2d7690df9cadc11a2853e1349dfe73373c15fc36d48265c992436205016cc9f95e118ba9cce4693ee38af0639efcfe3570e268c61d
18 |
19 | # Do not keep production secrets in the repository,
20 | # instead read values from the environment.
21 | production:
22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
23 |
--------------------------------------------------------------------------------
/test/fixtures/users.yml:
--------------------------------------------------------------------------------
1 | michael:
2 | name: Michael Example
3 | email: michael@example.com
4 | password_digest: <%= User.digest('password') %>
5 | admin: true
6 | activated: true
7 | activated_at: <%= Time.zone.now %>
8 |
9 | archer:
10 | name: Sterling Archer
11 | email: duchess@example.gov
12 | password_digest: <%= User.digest('password') %>
13 | activated: true
14 | activated_at: <%= Time.zone.now %>
15 |
16 | lana:
17 | name: Lana Kane
18 | email: hands@example.gov
19 | password_digest: <%= User.digest('password') %>
20 | activated: true
21 | activated_at: <%= Time.zone.now %>
22 |
23 | malory:
24 | name: Malory Archer
25 | email: boss@example.gov
26 | password_digest: <%= User.digest('password') %>
27 | activated: true
28 | activated_at: <%= Time.zone.now %>
29 |
30 | <% 30.times do |n| %>
31 | user_<%= n %>:
32 | name: <%= "User #{n}" %>
33 | email: <%= "user-#{n}@example.com" %>
34 | password_digest: <%= User.digest('password') %>
35 | activated: true
36 | activated_at: <%= Time.zone.now %>
37 | <% end %>
38 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV['RAILS_ENV'] ||= 'test'
2 | require File.expand_path('../../config/environment', __FILE__)
3 | require 'rails/test_help'
4 | require "minitest/reporters"
5 | Minitest::Reporters.use!
6 |
7 | class ActiveSupport::TestCase
8 | fixtures :all
9 | include ApplicationHelper
10 |
11 | # Returns true if a test user is logged in.
12 | def is_logged_in?
13 | !session[:user_id].nil?
14 | end
15 |
16 | # Logs in a test user.
17 | def log_in_as(user, options = {})
18 | password = options[:password] || 'password'
19 | remember_me = options[:remember_me] || '1'
20 | if integration_test?
21 | post login_path, session: { email: user.email,
22 | password: password,
23 | remember_me: remember_me }
24 | else
25 | session[:user_id] = user.id
26 | end
27 | end
28 |
29 | private
30 |
31 | # Returns true inside an integration test.
32 | def integration_test?
33 | defined?(post_via_redirect)
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # Users
2 | User.create!(name: "Example User",
3 | email: "example@railstutorial.org",
4 | password: "foobar",
5 | password_confirmation: "foobar",
6 | admin: true,
7 | activated: true,
8 | activated_at: Time.zone.now)
9 |
10 | 99.times do |n|
11 | name = Faker::Name.name
12 | email = "example-#{n+1}@railstutorial.org"
13 | password = "password"
14 | User.create!(name: name,
15 | email: email,
16 | password: password,
17 | password_confirmation: password,
18 | activated: true,
19 | activated_at: Time.zone.now)
20 | end
21 |
22 | # Microposts
23 | users = User.order(:created_at).take(6)
24 | 50.times do
25 | content = Faker::Lorem.sentence(5)
26 | users.each { |user| user.microposts.create!(content: content) }
27 | end
28 |
29 | # Following relationships
30 | users = User.all
31 | user = users.first
32 | following = users[2..50]
33 | followers = users[3..40]
34 | following.each { |followed| user.follow(followed) }
35 | followers.each { |follower| follower.follow(user) }
36 |
--------------------------------------------------------------------------------
/app/views/layouts/_header.html.erb:
--------------------------------------------------------------------------------
1 |
30 |
--------------------------------------------------------------------------------
/test/fixtures/microposts.yml:
--------------------------------------------------------------------------------
1 | orange:
2 | content: "I just ate an orange!"
3 | created_at: <%= 10.minutes.ago %>
4 | user: michael
5 |
6 | tau_manifesto:
7 | content: "Check out the @tauday site by @mhartl: http://tauday.com"
8 | created_at: <%= 3.years.ago %>
9 |
10 | cat_video:
11 | content: "Sad cats are sad: http://youtu.be/PKffm2uI4dk"
12 | created_at: <%= 2.hours.ago %>
13 |
14 | most_recent:
15 | content: "Writing a short test"
16 | created_at: <%= Time.zone.now %>
17 |
18 | <% 30.times do |n| %>
19 | micropost_<%= n %>:
20 | content: <%= Faker::Lorem.sentence(5) %>
21 | created_at: <%= 42.days.ago %>
22 | user: michael
23 | <% end %>
24 |
25 | ants:
26 | content: "Oh, is that what you want? Because that's how you get ants!"
27 | created_at: <%= 2.years.ago %>
28 | user: archer
29 |
30 | zone:
31 | content: "Danger zone!"
32 | created_at: <%= 3.days.ago %>
33 | user: archer
34 |
35 | tone:
36 | content: "I'm sorry. Your words made sense, but your sarcastic tone did not."
37 | created_at: <%= 10.minutes.ago %>
38 | user: lana
39 |
40 | van:
41 | content: "Dude, this van's, like, rolling probable cause."
42 | created_at: <%= 4.hours.ago %>
43 | user: lana
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'rails', '4.2.2'
4 | gem 'bcrypt', '3.1.7'
5 | gem 'faker', '1.4.2'
6 | gem 'carrierwave', '0.10.0'
7 | gem 'mini_magick', '3.8.0'
8 | gem 'fog', '1.36.0'
9 | gem 'will_paginate', '3.0.7'
10 | gem 'bootstrap-will_paginate', '0.0.10'
11 | gem 'bootstrap-sass', '3.2.0.0'
12 | gem 'sass-rails', '5.0.2'
13 | gem 'uglifier', '2.5.3'
14 | gem 'coffee-rails', '4.1.0'
15 | gem 'jquery-rails', '4.0.3'
16 | gem 'turbolinks', '2.3.0'
17 | gem 'jbuilder', '2.2.3'
18 | gem 'sdoc', '0.4.0', group: :doc
19 |
20 | group :development, :test do
21 | gem 'sqlite3', '1.3.9'
22 | gem 'byebug', '3.4.0'
23 | gem 'web-console', '2.0.0.beta3'
24 | gem 'spring', '1.1.3'
25 | end
26 |
27 | group :test do
28 | gem 'minitest-reporters', '1.0.5'
29 | gem 'mini_backtrace', '0.1.3'
30 | gem 'guard-minitest', '2.3.1'
31 | end
32 |
33 | group :production do
34 | gem 'pg', '0.17.1'
35 | gem 'rails_12factor', '0.0.2'
36 | gem 'puma', '2.11.1'
37 | end
38 |
--------------------------------------------------------------------------------
/test/integration/users_login_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersLoginTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | @user = users(:michael)
7 | end
8 |
9 | test "login with valid information followed by logout" do
10 | get login_path
11 | post login_path, session: { email: @user.email, password: 'password' }
12 | assert is_logged_in?
13 | follow_redirect!
14 | assert_template 'users/show'
15 | assert_select "a[href=?]", login_path, count: 0
16 | assert_select "a[href=?]", logout_path
17 | assert_select "a[href=?]", user_path(@user)
18 | delete logout_path
19 | assert_not is_logged_in?
20 | assert_redirected_to root_url
21 | # Simulate a user clicking logout in a second window.
22 | delete logout_path
23 | follow_redirect!
24 | assert_select "a[href=?]", login_path
25 | assert_select "a[href=?]", logout_path, count: 0
26 | assert_select "a[href=?]", user_path(@user), count: 0
27 | end
28 |
29 | test "login with remembering" do
30 | log_in_as(@user, remember_me: '1')
31 | assert_equal cookies['remember_token'], assigns(:user).remember_token
32 | end
33 |
34 | test "login without remembering" do
35 | log_in_as(@user, remember_me: '0')
36 | assert_nil cookies['remember_token']
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | require 'rails/all'
4 |
5 | # Require the gems listed in Gemfile, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(*Rails.groups)
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 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
16 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
17 | # config.time_zone = 'Central Time (US & Canada)'
18 |
19 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
20 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
21 | # config.i18n.default_locale = :de
22 |
23 | # Do not swallow errors in after_commit/after_rollback callbacks.
24 | config.active_record.raise_in_transactional_callbacks = true
25 |
26 | # Include the authenticity token in remote forms.
27 | config.action_view.embed_authenticity_token_in_remote_forms = true
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/app/helpers/sessions_helper.rb:
--------------------------------------------------------------------------------
1 | module SessionsHelper
2 |
3 | # Logs in the given user.
4 | def log_in(user)
5 | session[:user_id] = user.id
6 | end
7 |
8 | # Forgets a persistent session.
9 | def forget(user)
10 | user.forget
11 | cookies.delete(:user_id)
12 | cookies.delete(:remember_token)
13 | end
14 |
15 | # Logs out the current user.
16 | def log_out
17 | forget(current_user)
18 | session.delete(:user_id)
19 | @current_user = nil
20 | end
21 |
22 | # Remembers a user in a persistent session.
23 | def remember(user)
24 | user.remember
25 | cookies.permanent.signed[:user_id] = user.id
26 | cookies.permanent[:remember_token] = user.remember_token
27 | end
28 |
29 | # Returns the current logged-in user (if any).
30 | def current_user
31 | if (user_id = session[:user_id])
32 | @current_user ||= User.find_by(id: user_id)
33 | elsif (user_id = cookies.signed[:user_id])
34 | user = User.find_by(id: user_id)
35 | if user && user.authenticated?(:remember, cookies[:remember_token])
36 | log_in user
37 | @current_user = user
38 | end
39 | end
40 | end
41 |
42 | # Returns true if the user is logged in, false otherwise.
43 | def logged_in?
44 | !current_user.nil?
45 | end
46 |
47 | def current_user?(user)
48 | user == current_user
49 | end
50 |
51 | # Redirects to stored location (or to the default).
52 | def redirect_back_or(default)
53 | redirect_to(session[:forwarding_url] || default)
54 | session.delete(:forwarding_url)
55 | end
56 |
57 | # Stores the URL trying to be accessed.
58 | def store_location
59 | session[:forwarding_url] = request.url if request.get?
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/test/integration/microposts_interface_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class MicropostsInterfaceTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | @user = users(:michael)
7 | end
8 |
9 | test "micropost interface" do
10 | log_in_as(@user)
11 | get root_path
12 | assert_select 'div.pagination'
13 | assert_select 'input[type=file]'
14 | # Invalid submission
15 | post microposts_path, micropost: { content: "" }
16 | assert_select 'div#error_explanation'
17 | # Valid submission
18 | content = "This micropost really ties the room together"
19 | picture = fixture_file_upload('test/fixtures/rails.png', 'image/png')
20 | assert_difference 'Micropost.count', 1 do
21 | post microposts_path, micropost: { content: content, picture: picture }
22 | end
23 | assert assigns(:micropost).picture?
24 | follow_redirect!
25 | assert_match content, response.body
26 | # Delete a post.
27 | assert_select 'a', 'delete'
28 | first_micropost = @user.microposts.paginate(page: 1).first
29 | assert_difference 'Micropost.count', -1 do
30 | delete micropost_path(first_micropost)
31 | end
32 | # Visit a different user.
33 | get user_path(users(:archer))
34 | assert_select 'a', { text: 'delete', count: 0 }
35 | end
36 |
37 | test "micropost sidebar count" do
38 | log_in_as(@user)
39 | get root_path
40 | assert_match "#{@user.microposts.count} microposts", response.body
41 | # User with zero microposts
42 | other_user = users(:malory)
43 | log_in_as(other_user)
44 | get root_path
45 | assert_match "0 microposts", response.body
46 | other_user.microposts.create!(content: "A micropost")
47 | get root_path
48 | assert_match "1 micropost", response.body
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/test/integration/users_signup_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersSignupTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | ActionMailer::Base.deliveries.clear
7 | end
8 |
9 | test "invalid signup information" do
10 | get signup_path
11 | assert_no_difference 'User.count' do
12 | post users_path, user: { name: "",
13 | email: "user@invalid",
14 | password: "foo",
15 | password_confirmation: "bar" }
16 | end
17 | assert_template 'users/new'
18 | assert_select 'div#error_explanation'
19 | assert_select 'div.field_with_errors'
20 | end
21 |
22 | test "valid signup information with account activation" do
23 | get signup_path
24 | assert_difference 'User.count', 1 do
25 | post users_path, user: { name: "Example User",
26 | email: "user@example.com",
27 | password: "password",
28 | password_confirmation: "password" }
29 | end
30 | assert_equal 1, ActionMailer::Base.deliveries.size
31 | user = assigns(:user)
32 | assert_not user.activated?
33 | # Try to log in before activation.
34 | log_in_as(user)
35 | assert_not is_logged_in?
36 | # Invalid activation token
37 | get edit_account_activation_path("invalid token")
38 | assert_not is_logged_in?
39 | # Valid token, wrong email
40 | get edit_account_activation_path(user.activation_token, email: 'wrong')
41 | assert_not is_logged_in?
42 | # Valid activation token
43 | get edit_account_activation_path(user.activation_token, email: user.email)
44 | assert user.reload.activated?
45 | follow_redirect!
46 | assert_template 'users/show'
47 | assert is_logged_in?
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/app/controllers/password_resets_controller.rb:
--------------------------------------------------------------------------------
1 | class PasswordResetsController < ApplicationController
2 | before_action :get_user, only: [:edit, :update]
3 | before_action :valid_user, only: [:edit, :update]
4 | before_action :check_expiration, only: [:edit, :update]
5 |
6 | def new
7 | end
8 |
9 | def create
10 | @user = User.find_by(email: params[:password_reset][:email].downcase)
11 | if @user
12 | @user.create_reset_digest
13 | @user.send_password_reset_email
14 | flash[:info] = "Email sent with password reset instructions"
15 | redirect_to root_url
16 | else
17 | flash.now[:danger] = "Email address not found"
18 | render 'new'
19 | end
20 | end
21 |
22 | def edit
23 | end
24 |
25 | def update
26 | if params[:user][:password].empty?
27 | @user.errors.add(:password, "can't be empty")
28 | render 'edit'
29 | elsif @user.update_attributes(user_params)
30 | log_in @user
31 | flash[:success] = "Password has been reset."
32 | redirect_to @user
33 | else
34 | render 'edit'
35 | end
36 | end
37 |
38 | private
39 |
40 | def user_params
41 | params.require(:user).permit(:password, :password_confirmation)
42 | end
43 |
44 | # Before filters
45 |
46 | def get_user
47 | @user = User.find_by(email: params[:email])
48 | end
49 |
50 | # Confirms a valid user.
51 | def valid_user
52 | unless (@user && @user.activated? &&
53 | @user.authenticated?(:reset, params[:id]))
54 | redirect_to root_url
55 | end
56 | end
57 |
58 | # Checks expiration of reset token.
59 | def check_expiration
60 | if @user.password_reset_expired?
61 | flash[:danger] = "Password reset has expired."
62 | redirect_to new_password_reset_url
63 | end
64 | end
65 | end
66 |
--------------------------------------------------------------------------------
/test/integration/users_edit_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersEditTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | @user = users(:michael)
7 | end
8 |
9 | test "unsuccessful edit" do
10 | log_in_as(@user)
11 | get edit_user_path(@user)
12 | assert_template 'users/edit'
13 | patch user_path(@user), user: { name: "",
14 | email: "foo@invalid",
15 | password: "foo",
16 | password_confirmation: "bar" }
17 | assert_template 'users/edit'
18 | end
19 |
20 | test "successful edit" do
21 | log_in_as(@user)
22 | get edit_user_path(@user)
23 | assert_template 'users/edit'
24 | name = "Foo Bar"
25 | email = "foo@bar.com"
26 | patch user_path(@user), user: { name: name,
27 | email: email,
28 | password: "",
29 | password_confirmation: "" }
30 | assert_not flash.empty?
31 | assert_redirected_to @user
32 | @user.reload
33 | assert_equal name, @user.name
34 | assert_equal email, @user.email
35 | end
36 |
37 | test "successful edit with friendly forwarding" do
38 | get edit_user_path(@user)
39 | log_in_as(@user)
40 | assert_redirected_to edit_user_path(@user)
41 | name = "Foo Bar"
42 | email = "foo@bar.com"
43 | patch user_path(@user), user: { name: name,
44 | email: email,
45 | password: "",
46 | password_confirmation: "" }
47 | assert_not flash.empty?
48 | assert_redirected_to @user
49 | @user.reload
50 | assert_equal name, @user.name
51 | assert_equal email, @user.email
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.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 web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports and disable caching.
13 | config.consider_all_requests_local = true
14 | config.action_controller.perform_caching = false
15 |
16 | # Don't care if the mailer can't send.
17 | config.action_mailer.raise_delivery_errors = true
18 | config.action_mailer.delivery_method = :test
19 | host = 'rails-tutorial-captainstack.c9users.io'
20 | config.action_mailer.default_url_options = { host: host }
21 |
22 | # Print deprecation notices to the Rails logger.
23 | config.active_support.deprecation = :log
24 |
25 | # Raise an error on page load if there are pending migrations.
26 | config.active_record.migration_error = :page_load
27 |
28 | # Debug mode disables concatenation and preprocessing of assets.
29 | # This option may cause significant delays in view rendering with a large
30 | # number of complex assets.
31 | config.assets.debug = true
32 |
33 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
34 | # yet still be able to expire them through the digest params.
35 | config.assets.digest = true
36 |
37 | # Adds additional error checking when serving assets at runtime.
38 | # Checks for improperly declared sprockets dependencies.
39 | # Raises helpful error messages.
40 | config.assets.raise_runtime_errors = true
41 |
42 | # Raises error for missing translations
43 | # config.action_view.raise_on_missing_translations = true
44 | end
45 |
--------------------------------------------------------------------------------
/Guardfile:
--------------------------------------------------------------------------------
1 | # Defines the matching rules for Guard.
2 | guard :minitest, spring: true, all_on_start: false do
3 | watch(%r{^test/(.*)/?(.*)_test\.rb$})
4 | watch('test/test_helper.rb') { 'test' }
5 | watch('config/routes.rb') { integration_tests }
6 | watch(%r{^app/models/(.*?)\.rb$}) do |matches|
7 | "test/models/#{matches[1]}_test.rb"
8 | end
9 | watch(%r{^app/controllers/(.*?)_controller\.rb$}) do |matches|
10 | resource_tests(matches[1])
11 | end
12 | watch(%r{^app/views/([^/]*?)/.*\.html\.erb$}) do |matches|
13 | ["test/controllers/#{matches[1]}_controller_test.rb"] +
14 | integration_tests(matches[1])
15 | end
16 | watch(%r{^app/helpers/(.*?)_helper\.rb$}) do |matches|
17 | integration_tests(matches[1])
18 | end
19 | watch('app/views/layouts/application.html.erb') do
20 | 'test/integration/site_layout_test.rb'
21 | end
22 | watch('app/helpers/sessions_helper.rb') do
23 | integration_tests << 'test/helpers/sessions_helper_test.rb'
24 | end
25 | watch('app/controllers/sessions_controller.rb') do
26 | ['test/controllers/sessions_controller_test.rb',
27 | 'test/integration/users_login_test.rb']
28 | end
29 | watch('app/controllers/account_activations_controller.rb') do
30 | 'test/integration/users_signup_test.rb'
31 | end
32 | watch(%r{app/views/users/*}) do
33 | resource_tests('users') +
34 | ['test/integration/microposts_interface_test.rb']
35 | end
36 | end
37 |
38 | # Returns the integration tests corresponding to the given resource.
39 | def integration_tests(resource = :all)
40 | if resource == :all
41 | Dir["test/integration/*"]
42 | else
43 | Dir["test/integration/#{resource}_*.rb"]
44 | end
45 | end
46 |
47 | # Returns the controller tests corresponding to the given resource.
48 | def controller_test(resource)
49 | "test/controllers/#{resource}_controller_test.rb"
50 | end
51 |
52 | # Returns all tests for the given resource.
53 | def resource_tests(resource)
54 | integration_tests(resource) << controller_test(resource)
55 | end
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.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 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure static file server for tests with Cache-Control for performance.
16 | config.serve_static_files = true
17 | config.static_cache_control = 'public, max-age=3600'
18 |
19 | # Show full error reports and disable caching.
20 | config.consider_all_requests_local = true
21 | config.action_controller.perform_caching = false
22 |
23 | # Raise exceptions instead of rendering exception templates.
24 | config.action_dispatch.show_exceptions = false
25 |
26 | # Disable request forgery protection in test environment.
27 | config.action_controller.allow_forgery_protection = false
28 |
29 | # Tell Action Mailer not to deliver emails to the real world.
30 | # The :test delivery method accumulates sent emails in the
31 | # ActionMailer::Base.deliveries array.
32 | config.action_mailer.delivery_method = :test
33 | config.action_mailer.default_url_options = { host: 'rails-tutorial-captainstack.c9users.io' }
34 |
35 | # Randomize the order test cases are executed.
36 | config.active_support.test_order = :random
37 |
38 | # Print deprecation notices to the stderr.
39 | config.active_support.deprecation = :stderr
40 |
41 | # Raises error for missing translations
42 | # config.action_view.raise_on_missing_translations = true
43 | end
44 |
--------------------------------------------------------------------------------
/test/integration/following_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class FollowingTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | @user = users(:michael)
7 | @other = users(:archer)
8 | log_in_as(@user)
9 | end
10 |
11 | test "following page" do
12 | get following_user_path(@user)
13 | assert_not @user.following.empty?
14 | assert_match @user.following.count.to_s, response.body
15 | @user.following.each do |user|
16 | assert_select "a[href=?]", user_path(user)
17 | end
18 | end
19 |
20 | test "followers page" do
21 | get followers_user_path(@user)
22 | assert_not @user.followers.empty?
23 | assert_match @user.followers.count.to_s, response.body
24 | @user.followers.each do |user|
25 | assert_select "a[href=?]", user_path(user)
26 | end
27 | end
28 |
29 | test "should follow a user the standard way" do
30 | assert_difference '@user.following.count', 1 do
31 | post relationships_path, followed_id: @other.id
32 | end
33 | end
34 |
35 | test "should follow a user with Ajax" do
36 | assert_difference '@user.following.count', 1 do
37 | xhr :post, relationships_path, followed_id: @other.id
38 | end
39 | end
40 |
41 | test "should unfollow a user the standard way" do
42 | @user.follow(@other)
43 | relationship = @user.active_relationships.find_by(followed_id: @other.id)
44 | assert_difference '@user.following.count', -1 do
45 | delete relationship_path(relationship)
46 | end
47 | end
48 |
49 | test "should unfollow a user with Ajax" do
50 | @user.follow(@other)
51 | relationship = @user.active_relationships.find_by(followed_id: @other.id)
52 | assert_difference '@user.following.count', -1 do
53 | xhr :delete, relationship_path(relationship)
54 | end
55 | end
56 |
57 | test "feed on Home page" do
58 | get root_path
59 | @user.feed.paginate(page: 1).each do |micropost|
60 | assert_match CGI.escapeHTML(micropost.content), response.body
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/app/controllers/users_controller.rb:
--------------------------------------------------------------------------------
1 | class UsersController < ApplicationController
2 | before_action :logged_in_user, only: [:index, :edit, :update, :destroy, :following, :followers]
3 | before_action :correct_user, only: [:edit, :update]
4 | before_action :admin_user, only: :destroy
5 |
6 | def index
7 | @users = User.where(activated: true).paginate(page: params[:page])
8 | end
9 |
10 | def show
11 | @user = User.find(params[:id])
12 | @microposts = @user.microposts.paginate(page: params[:page])
13 | redirect_to root_url and return unless @user.activated?
14 | end
15 |
16 | def new
17 | @user = User.new
18 | end
19 |
20 | def create
21 | @user = User.new(user_params)
22 | if @user.save
23 | @user.send_activation_email
24 | flash[:info] = "Please check your email to activate your account."
25 | redirect_to root_url
26 | else
27 | render 'new'
28 | end
29 | end
30 |
31 | def edit
32 | @user = User.find(params[:id])
33 | end
34 |
35 | def update
36 | @user = User.find(params[:id])
37 | if @user.update_attributes(user_params)
38 | flash[:success] = "Profile updated"
39 | redirect_to @user
40 | else
41 | render 'edit'
42 | end
43 | end
44 |
45 | def destroy
46 | User.find(params[:id]).destroy
47 | flash[:success] = "User deleted"
48 | redirect_to root_url
49 | end
50 |
51 | def following
52 | @title = "Following"
53 | @user = User.find(params[:id])
54 | @users = @user.following.paginate(page: params[:page])
55 | render 'show_follow'
56 | end
57 |
58 | def followers
59 | @title = "Followers"
60 | @user = User.find(params[:id])
61 | @users = @user.followers.paginate(page: params[:page])
62 | render 'show_follow'
63 | end
64 |
65 | private
66 |
67 | def user_params
68 | params.require(:user).permit(:name, :email, :password, :password_confirmation, :admin)
69 | end
70 |
71 | # Before filters
72 |
73 | # Confirms the correct user.
74 | def correct_user
75 | @user = User.find(params[:id])
76 | redirect_to(root_url) unless current_user?(@user)
77 | end
78 |
79 | # Confirms an admin user
80 | def admin_user
81 | redirect_to(root_url) unless current_user.admin?
82 | end
83 | end
--------------------------------------------------------------------------------
/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 that you check this file into your version control system.
13 |
14 | ActiveRecord::Schema.define(version: 20160301020419) do
15 |
16 | create_table "microposts", force: :cascade do |t|
17 | t.text "content"
18 | t.integer "user_id"
19 | t.datetime "created_at", null: false
20 | t.datetime "updated_at", null: false
21 | t.string "picture"
22 | end
23 |
24 | add_index "microposts", ["user_id", "created_at"], name: "index_microposts_on_user_id_and_created_at"
25 | add_index "microposts", ["user_id"], name: "index_microposts_on_user_id"
26 |
27 | create_table "relationships", force: :cascade do |t|
28 | t.integer "follower_id"
29 | t.integer "followed_id"
30 | t.datetime "created_at", null: false
31 | t.datetime "updated_at", null: false
32 | end
33 |
34 | add_index "relationships", ["followed_id"], name: "index_relationships_on_followed_id"
35 | add_index "relationships", ["follower_id", "followed_id"], name: "index_relationships_on_follower_id_and_followed_id", unique: true
36 | add_index "relationships", ["follower_id"], name: "index_relationships_on_follower_id"
37 |
38 | create_table "users", force: :cascade do |t|
39 | t.string "name"
40 | t.string "email"
41 | t.datetime "created_at", null: false
42 | t.datetime "updated_at", null: false
43 | t.string "password_digest"
44 | t.string "remember_digest"
45 | t.boolean "admin"
46 | t.string "activation_digest"
47 | t.boolean "activated", default: false
48 | t.datetime "activated_at"
49 | t.string "reset_digest"
50 | t.datetime "reset_sent_at"
51 | end
52 |
53 | add_index "users", ["email"], name: "index_users_on_email", unique: true
54 |
55 | end
56 |
--------------------------------------------------------------------------------
/test/controllers/users_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersControllerTest < ActionController::TestCase
4 |
5 | def setup
6 | @user = users(:michael)
7 | @other_user = users(:archer)
8 | end
9 |
10 | test "should redirect index when not logged in" do
11 | get :index
12 | assert_redirected_to login_url
13 | end
14 |
15 | test "should get new" do
16 | get :new
17 | assert_response :success
18 | end
19 |
20 | test "should redirect edit when not logged in" do
21 | get :edit, id: @user
22 | assert_not flash.empty?
23 | assert_redirected_to login_url
24 | end
25 |
26 | test "should redirect update when not logged in" do
27 | patch :update, id: @user, user: { name: @user.name, email: @user.email }
28 | assert_not flash.empty?
29 | assert_redirected_to login_url
30 | end
31 |
32 | test "should redirect edit when logged in as wrong user" do
33 | log_in_as(@other_user)
34 | get :edit, id: @user
35 | assert flash.empty?
36 | assert_redirected_to root_url
37 | end
38 |
39 | test "should redirect update when logged in as wrong user" do
40 | log_in_as(@other_user)
41 | patch :update, id: @user, user: { name: @user.name, email: @user.email }
42 | assert flash.empty?
43 | assert_redirected_to root_url
44 | end
45 |
46 | test "should not allow the admin attribute to be edited via the web" do
47 | log_in_as(@other_user)
48 | assert_not @other_user.admin?
49 | patch :update, id: @other_user, user: { password: @other_user.password,
50 | password_confirmation: @other_user.password,
51 | admin: 1 }
52 | assert_not @other_user.reload.admin?
53 | end
54 |
55 | test "should redirect destroy when not logged in" do
56 | assert_no_difference 'User.count' do
57 | delete :destroy, id: @user
58 | end
59 | assert_redirected_to login_url
60 | end
61 |
62 | test "should redirect destroy when logged in as a non-admin" do
63 | log_in_as(@other_user)
64 | assert_no_difference 'User.count' do
65 | delete :destroy, id: @user
66 | end
67 | assert_redirected_to root_url
68 | end
69 |
70 | test "should redirect following when not logged in" do
71 | get :following, id: @user
72 | assert_redirected_to login_url
73 | end
74 |
75 | test "should redirect followers when not logged in" do
76 | get :followers, id: @user
77 | assert_redirected_to login_url
78 | end
79 | end
80 |
--------------------------------------------------------------------------------
/test/integration/password_resets_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class PasswordResetsTest < ActionDispatch::IntegrationTest
4 |
5 | def setup
6 | ActionMailer::Base.deliveries.clear
7 | @user = users(:michael)
8 | end
9 |
10 | test "password resets" do
11 | get new_password_reset_path
12 | assert_template 'password_resets/new'
13 | # Invalid email
14 | post password_resets_path, password_reset: { email: "" }
15 | assert_not flash.empty?
16 | assert_template 'password_resets/new'
17 | # Valid email
18 | post password_resets_path, password_reset: { email: @user.email }
19 | assert_not_equal @user.reset_digest, @user.reload.reset_digest
20 | assert_equal 1, ActionMailer::Base.deliveries.size
21 | assert_not flash.empty?
22 | assert_redirected_to root_url
23 | # Password reset form
24 | user = assigns(:user)
25 | # Wrong email
26 | get edit_password_reset_path(user.reset_token, email: "")
27 | assert_redirected_to root_url
28 | # Inactive user
29 | user.toggle!(:activated)
30 | get edit_password_reset_path(user.reset_token, email: user.email)
31 | assert_redirected_to root_url
32 | user.toggle!(:activated)
33 | # Right email, wrong token
34 | get edit_password_reset_path('wrong token', email: user.email)
35 | assert_redirected_to root_url
36 | # Right email, right token
37 | get edit_password_reset_path(user.reset_token, email: user.email)
38 | assert_template 'password_resets/edit'
39 | assert_select "input[name=email][type=hidden][value=?]", user.email
40 | # Invalid password & confirmation
41 | patch password_reset_path(user.reset_token),
42 | email: user.email,
43 | user: { password: "foobaz",
44 | password_confirmation: "barquux" }
45 | assert_select 'div#error_explanation'
46 | # Empty password
47 | patch password_reset_path(user.reset_token),
48 | email: user.email,
49 | user: { password: "",
50 | password_confirmation: "" }
51 | assert_select 'div#error_explanation'
52 | # Valid password & confirmation
53 | patch password_reset_path(user.reset_token),
54 | email: user.email,
55 | user: { password: "foobaz",
56 | password_confirmation: "foobaz" }
57 | assert is_logged_in?
58 | assert_not flash.empty?
59 | assert_redirected_to user
60 | end
61 |
62 | test "expired token" do
63 | get new_password_reset_path
64 | post password_resets_path, password_reset: { email: @user.email }
65 |
66 | @user = assigns(:user)
67 | @user.update_attribute(:reset_sent_at, 3.hours.ago)
68 | patch password_reset_path(@user.reset_token),
69 | email: @user.email,
70 | user: { password: "foobar",
71 | password_confirmation: "foobar" }
72 | assert_response :redirect
73 | follow_redirect!
74 | assert_match /expired/i, response.body
75 | end
76 | end
77 |
--------------------------------------------------------------------------------
/test/models/user_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UserTest < ActiveSupport::TestCase
4 |
5 | def setup
6 | @user = User.new(name: "Example User", email: "user@example.com", password: "foobar", password_confirmation: "foobar")
7 | end
8 |
9 | test "should be valid" do
10 | assert @user.valid?
11 | end
12 |
13 | test "name should be present" do
14 | @user.name = " "
15 | assert_not @user.valid?
16 | end
17 |
18 | test "name should not be too long" do
19 | @user.name = "a" * 51
20 | assert_not @user.valid?
21 | end
22 |
23 | test "email should not be too long" do
24 | @user.email = "a" * 244 + "@example.com"
25 | assert_not @user.valid?
26 | end
27 |
28 | test "email validation should accept valid addresses" do
29 | valid_addresses = %w[user@example.com USER@foo.COM A_US-ER@foo.bar.org first.last@foo.jp alice+bob@baz.cn]
30 | valid_addresses.each do |valid_address|
31 | @user.email = valid_address
32 | assert @user.valid?, "#{valid_address.inspect} should be valid"
33 | end
34 | end
35 |
36 | test "email validation should reject invalid addresses" do
37 | invalid_addresses = %w[user@example,com user_at_foo.org user.name@example. foo@bar_baz.com foo@bar+baz.com]
38 | invalid_addresses.each do |invalid_address|
39 | @user.email = invalid_address
40 | assert_not @user.valid?, "#{invalid_address.inspect} should be invalid"
41 | end
42 | end
43 |
44 | test "email addresses should be unique" do
45 | duplicate_user = @user.dup
46 | duplicate_user.email = @user.email.upcase
47 | @user.save
48 | assert_not duplicate_user.valid?
49 | end
50 |
51 | test "password should be present (nonblank)" do
52 | @user.password = @user.password_confirmation = " " * 6
53 | assert_not @user.valid?
54 | end
55 |
56 | test "email addresses should be saved as lower-case" do
57 | mixed_case_email = "Foo@ExAMPle.CoM"
58 | @user.email = mixed_case_email
59 | @user.save
60 | assert_equal mixed_case_email.downcase, @user.reload.email
61 | end
62 |
63 | test "password should have a minimum length" do
64 | @user.password = @user.password_confirmation = "a" * 5
65 | assert_not @user.valid?
66 | end
67 |
68 | test "authenticated? should return false for a user with nil digest" do
69 | assert_not @user.authenticated?(:remember, '')
70 | end
71 |
72 | test "associated microposts should be destroyed" do
73 | @user.save
74 | @user.microposts.create!(content: "Lorem ipsum")
75 | assert_difference 'Micropost.count', -1 do
76 | @user.destroy
77 | end
78 | end
79 |
80 | test "should follow and unfollow a user" do
81 | michael = users(:michael)
82 | archer = users(:archer)
83 | assert_not michael.following?(archer)
84 | michael.follow(archer)
85 | assert michael.following?(archer)
86 | assert archer.followers.include?(michael)
87 | michael.unfollow(archer)
88 | assert_not michael.following?(archer)
89 | end
90 |
91 | test "feed should have the right posts" do
92 | michael = users(:michael)
93 | archer = users(:archer)
94 | lana = users(:lana)
95 | # Posts from followed user
96 | lana.microposts.each do |post_following|
97 | assert michael.feed.include?(post_following)
98 | end
99 | # Posts from self
100 | michael.microposts.each do |post_self|
101 | assert michael.feed.include?(post_self)
102 | end
103 | # Posts from unfollowed user
104 | archer.microposts.each do |post_unfollowed|
105 | assert_not michael.feed.include?(post_unfollowed)
106 | end
107 | end
108 | end
109 |
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Code is not reloaded between requests.
5 | config.cache_classes = true
6 |
7 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application
18 | # Add `rack-cache` to your Gemfile before enabling this.
19 | # For large-scale production use, consider using a caching reverse proxy like
20 | # NGINX, varnish or squid.
21 | # config.action_dispatch.rack_cache = true
22 |
23 | # Disable serving static files from the `/public` folder by default since
24 | # Apache or NGINX already handles this.
25 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
26 |
27 | # Compress JavaScripts and CSS.
28 | config.assets.js_compressor = :uglifier
29 | # config.assets.css_compressor = :sass
30 |
31 | # Do not fallback to assets pipeline if a precompiled asset is missed.
32 | config.assets.compile = false
33 |
34 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
35 | # yet still be able to expire them through the digest params.
36 | config.assets.digest = true
37 |
38 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
39 |
40 | # Specifies the header that your server uses for sending files.
41 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
42 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
43 |
44 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
45 | config.force_ssl = true
46 |
47 | # Use the lowest log level to ensure availability of diagnostic information
48 | # when problems arise.
49 | config.log_level = :debug
50 |
51 | # Prepend all log lines with the following tags.
52 | # config.log_tags = [ :subdomain, :uuid ]
53 |
54 | # Use a different logger for distributed setups.
55 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
56 |
57 | # Use a different cache store in production.
58 | # config.cache_store = :mem_cache_store
59 |
60 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
61 | # config.action_controller.asset_host = 'http://assets.example.com'
62 |
63 | # Ignore bad email addresses and do not raise email delivery errors.
64 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
65 | config.action_mailer.raise_delivery_errors = true
66 | config.action_mailer.delivery_method = :smtp
67 | host = '.herokuapp.com'
68 | config.action_mailer.default_url_options = { host: 'pacific-spire-36298.herokuapp.com' }
69 | ActionMailer::Base.smtp_settings = {
70 | :address => 'smtp.sendgrid.net',
71 | :port => '587',
72 | :authentication => :plain,
73 | :user_name => ENV['SENDGRID_USERNAME'],
74 | :password => ENV['SENDGRID_PASSWORD'],
75 | :domain => 'heroku.com',
76 | :enable_starttls_auto => true
77 | }
78 |
79 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
80 | # the I18n.default_locale when a translation cannot be found).
81 | config.i18n.fallbacks = true
82 |
83 | # Send deprecation notices to registered listeners.
84 | config.active_support.deprecation = :notify
85 |
86 | # Use default logging formatter so that PID and timestamp are not suppressed.
87 | config.log_formatter = ::Logger::Formatter.new
88 |
89 | # Do not dump schema after migrations.
90 | config.active_record.dump_schema_after_migration = false
91 | end
92 |
--------------------------------------------------------------------------------
/app/models/user.rb:
--------------------------------------------------------------------------------
1 | class User < ActiveRecord::Base
2 | has_many :microposts, dependent: :destroy
3 | has_many :active_relationships, class_name: "Relationship",
4 | foreign_key: "follower_id",
5 | dependent: :destroy
6 | has_many :passive_relationships, class_name: "Relationship",
7 | foreign_key: "followed_id",
8 | dependent: :destroy
9 | has_many :following, through: :active_relationships, source: :followed
10 | has_many :followers, through: :passive_relationships, source: :follower
11 | attr_accessor :remember_token, :activation_token, :reset_token
12 | before_save :downcase_email
13 | before_create :create_activation_digest
14 | validates :name, presence: true, length: { maximum: 50 }
15 | VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
16 | validates :email, presence: true, length: { maximum: 255 },
17 | format: { with: VALID_EMAIL_REGEX },
18 | uniqueness: { case_sensitive: false }
19 | has_secure_password
20 | validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
21 |
22 | class << self
23 | # Returns the hash digest of the given string.
24 | def digest(string)
25 | cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
26 | BCrypt::Engine.cost
27 | BCrypt::Password.create(string, cost: cost)
28 | end
29 |
30 | # Returns a random token.
31 | def new_token
32 | SecureRandom.urlsafe_base64
33 | end
34 | end
35 |
36 | def User.digest(string)
37 | cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
38 | BCrypt::Password.create(string, cost: cost)
39 | end
40 |
41 | # Remembers a user in the database for use in persistent sessions.
42 | def remember
43 | self.remember_token = User.new_token
44 | update_attribute(:remember_digest, User.digest(remember_token))
45 | end
46 |
47 | # Returns true if the given token matches the digest.
48 | def authenticated?(attribute, token)
49 | digest = send("#{attribute}_digest")
50 | return false if digest.nil?
51 | BCrypt::Password.new(digest).is_password?(token)
52 | end
53 |
54 | # Forgets a user.
55 | def forget
56 | update_attribute(:remember_digest, nil)
57 | end
58 |
59 | # Activates an account.
60 | def activate
61 | update_columns(activated: true, activated_at: Time.zone.now)
62 | end
63 |
64 | # Sends activation email.
65 | def send_activation_email
66 | UserMailer.account_activation(self).deliver_now
67 | end
68 |
69 | # Sets the password reset attributes.
70 | def create_reset_digest
71 | self.reset_token = User.new_token
72 | update_columns(reset_digest: User.digest(reset_token), reset_sent_at: Time.zone.now)
73 | end
74 |
75 | # Sends password reset email.
76 | def send_password_reset_email
77 | UserMailer.password_reset(self).deliver_now
78 | end
79 |
80 | # Returns true if a password reset has expired.
81 | def password_reset_expired?
82 | reset_sent_at < 2.hours.ago
83 | end
84 |
85 | # Returns a user's status feed.
86 | def feed
87 | following_ids = "SELECT followed_id FROM relationships
88 | WHERE follower_id = :user_id"
89 | Micropost.where("user_id IN (#{following_ids})
90 | OR user_id = :user_id", user_id: id)
91 | end
92 |
93 | # Follows a user.
94 | def follow(other_user)
95 | active_relationships.create(followed_id: other_user.id)
96 | end
97 |
98 | # Unfollows a user.
99 | def unfollow(other_user)
100 | active_relationships.find_by(followed_id: other_user.id).destroy
101 | end
102 |
103 | # Returns true if the current user is following the other user.
104 | def following?(other_user)
105 | following.include?(other_user)
106 | end
107 |
108 | private
109 |
110 | # Converts email to all lower-case.
111 | def downcase_email
112 | self.email = email.downcase
113 | end
114 |
115 | # Creates and assigns the activation token and digest.
116 | def create_activation_digest
117 | self.activation_token = User.new_token
118 | self.activation_digest = User.digest(activation_token)
119 | end
120 | end
121 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/custom.css.scss:
--------------------------------------------------------------------------------
1 | @import "bootstrap-sprockets";
2 | @import "bootstrap";
3 |
4 | /* mixins, variables, etc. */
5 |
6 | $gray-medium-light: #eaeaea;
7 |
8 | @mixin box_sizing {
9 | -mox-box-sizing: border-box;
10 | -webkit-box-sizing: border-box;
11 | box-sizing: border-box;
12 | }
13 |
14 | /* universal */
15 |
16 | body {
17 | padding-top: 60px;
18 | }
19 |
20 | section {
21 | overflow: auto;
22 | }
23 |
24 | textarea {
25 | resize: vertical;
26 | }
27 |
28 | .center {
29 | text-align: center;
30 | h1 {
31 | margin-bottom: 10px;
32 | }
33 | }
34 |
35 | /* typography */
36 |
37 | h1, h2, h3, h4, h5, h6 {
38 | line-height: 1;
39 | }
40 |
41 | h1 {
42 | font-size: 3em;
43 | letter-spacing: -2px;
44 | margin-bottom: 30px;
45 | text-align: center;
46 | }
47 |
48 | h2 {
49 | font-size: 1.2em;
50 | letter-spacing: -1px;
51 | margin-bottom: 30px;
52 | text-align: center;
53 | font-weight: normal;
54 | color: $gray-light;
55 | }
56 |
57 | p {
58 | font-size: 1.1em;
59 | line-height: 1.7em;
60 | }
61 |
62 |
63 | /* header */
64 |
65 | #logo {
66 | float: left;
67 | margin-right: 10px;
68 | font-size: 1.7em;
69 | color: white;
70 | text-transform: uppercase;
71 | letter-spacing: -1px;
72 | padding-top: 9px;
73 | font-weight: bold;
74 | &:hover {
75 | color: white;
76 | text-decoration: none;
77 | }
78 | }
79 |
80 | /* footer */
81 |
82 | footer {
83 | margin-top: 45px;
84 | padding-top: 5px;
85 | border-top: 1px solid $gray-medium-light;
86 | color: $gray-light;
87 | a {
88 | color: $gray;
89 | &:hover {
90 | color: $gray-darker;
91 | }
92 | }
93 | small {
94 | float: left;
95 | }
96 | ul {
97 | float: right;
98 | list-style: none;
99 | li {
100 | float: left;
101 | margin-left: 15px;
102 | }
103 | }
104 | }
105 |
106 | /* miscellaneous */
107 |
108 | .debug_dump {
109 | clear: both;
110 | float: left;
111 | width: 100%;
112 | margin-top: 45px;
113 | @include box_sizing;
114 | }
115 |
116 | /* sidebar */
117 |
118 | aside {
119 | section.user_info {
120 | margin-top: 20px;
121 | }
122 | section {
123 | padding: 10px 0;
124 | margin-top: 20px;
125 | &:first-child {
126 | border: 0;
127 | padding-top: 0;
128 | }
129 | span {
130 | display: block;
131 | margin-bottom: 3px;
132 | line-height: 1;
133 | }
134 | h1 {
135 | font-size: 1.4em;
136 | text-align: left;
137 | letter-spacing: -1px;
138 | margin-bottom: 3px;
139 | margin-top: 0px;
140 | }
141 | }
142 | }
143 |
144 | .gravatar {
145 | float: left;
146 | margin-right: 10px;
147 | }
148 |
149 | .gravatar_edit {
150 | margin-top: 15px;
151 | }
152 |
153 | .stats {
154 | overflow: auto;
155 | margin-top: 0;
156 | padding: 0;
157 | a {
158 | float: left;
159 | padding: 0 10px;
160 | border-left: 1px solid $gray-lighter;
161 | color: gray;
162 | &:first-child {
163 | padding-left: 0;
164 | border: 0;
165 | }
166 | &:hover {
167 | text-decoration: none;
168 | color: blue;
169 | }
170 | }
171 | strong {
172 | display: block;
173 | }
174 | }
175 |
176 | .user_avatars {
177 | overflow: auto;
178 | margin-top: 10px;
179 | .gravatar {
180 | margin: 1px 1px;
181 | }
182 | a {
183 | padding: 0;
184 | }
185 | }
186 |
187 | .users.follow {
188 | padding: 0;
189 | }
190 |
191 | /* forms */
192 |
193 | input, textarea, select, .uneditable-input {
194 | border: 1px solid #bbb;
195 | width: 100%;
196 | margin-bottom: 15px;
197 | @include box_sizing;
198 | }
199 |
200 | input {
201 | height: auto !important;
202 | }
203 |
204 | #error_explanation {
205 | color: red;
206 | ul {
207 | color: red;
208 | margin: 0 0 30px 0;
209 | }
210 | }
211 |
212 | .field_with_errors {
213 | @extend .has-error;
214 | .form-control {
215 | color: $state-danger-text;
216 | }
217 | }
218 |
219 | .checkbox {
220 | margin-top: -10px;
221 | margin-bottom: 10px;
222 | span {
223 | margin-left: 20px;
224 | font-weight: normal;
225 | }
226 | }
227 |
228 | #session_remember_me {
229 | width: auto;
230 | margin-left: 0;
231 | }
232 |
233 | /* Users index */
234 |
235 | .users {
236 | list-style: none;
237 | margin: 0;
238 | li {
239 | overflow: auto;
240 | padding: 10px 0;
241 | border-bottom: 1px solid $gray-lighter;
242 | }
243 | }
244 |
245 | /* microposts */
246 |
247 | .microposts {
248 | list-style: none;
249 | padding: 0;
250 | li {
251 | padding: 10px 0;
252 | border-top: 1px solid #e8e8e8;
253 | }
254 | .user {
255 | margin-top: 5em;
256 | padding-top: 0;
257 | }
258 | .content {
259 | display: block;
260 | margin-left: 60px;
261 | img {
262 | display: block;
263 | padding: 5px 0;
264 | }
265 | }
266 | .timestamp {
267 | color: $gray-light;
268 | display: block;
269 | margin-left: 60px;
270 | }
271 | .gravatar {
272 | float: left;
273 | margin-right: 10px;
274 | margin-top: 5px;
275 | }
276 | }
277 |
278 | aside {
279 | textarea {
280 | height: 100px;
281 | margin-bottom: 5px;
282 | }
283 | }
284 |
285 | span.picture {
286 | margin-top: 10px;
287 | input {
288 | border: 0;
289 | }
290 | }
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (2.3.2)
5 | actionmailer (4.2.2)
6 | actionpack (= 4.2.2)
7 | actionview (= 4.2.2)
8 | activejob (= 4.2.2)
9 | mail (~> 2.5, >= 2.5.4)
10 | rails-dom-testing (~> 1.0, >= 1.0.5)
11 | actionpack (4.2.2)
12 | actionview (= 4.2.2)
13 | activesupport (= 4.2.2)
14 | rack (~> 1.6)
15 | rack-test (~> 0.6.2)
16 | rails-dom-testing (~> 1.0, >= 1.0.5)
17 | rails-html-sanitizer (~> 1.0, >= 1.0.1)
18 | actionview (4.2.2)
19 | activesupport (= 4.2.2)
20 | builder (~> 3.1)
21 | erubis (~> 2.7.0)
22 | rails-dom-testing (~> 1.0, >= 1.0.5)
23 | rails-html-sanitizer (~> 1.0, >= 1.0.1)
24 | activejob (4.2.2)
25 | activesupport (= 4.2.2)
26 | globalid (>= 0.3.0)
27 | activemodel (4.2.2)
28 | activesupport (= 4.2.2)
29 | builder (~> 3.1)
30 | activerecord (4.2.2)
31 | activemodel (= 4.2.2)
32 | activesupport (= 4.2.2)
33 | arel (~> 6.0)
34 | activesupport (4.2.2)
35 | i18n (~> 0.7)
36 | json (~> 1.7, >= 1.7.7)
37 | minitest (~> 5.1)
38 | thread_safe (~> 0.3, >= 0.3.4)
39 | tzinfo (~> 1.1)
40 | ansi (1.5.0)
41 | arel (6.0.3)
42 | bcrypt (3.1.7)
43 | binding_of_caller (0.7.3.pre1)
44 | debug_inspector (>= 0.0.1)
45 | bootstrap-sass (3.2.0.0)
46 | sass (~> 3.2)
47 | bootstrap-will_paginate (0.0.10)
48 | will_paginate
49 | builder (3.2.2)
50 | byebug (3.4.0)
51 | columnize (~> 0.8)
52 | debugger-linecache (~> 1.2)
53 | slop (~> 3.6)
54 | carrierwave (0.10.0)
55 | activemodel (>= 3.2.0)
56 | activesupport (>= 3.2.0)
57 | json (>= 1.7)
58 | mime-types (>= 1.16)
59 | coderay (1.1.0)
60 | coffee-rails (4.1.0)
61 | coffee-script (>= 2.2.0)
62 | railties (>= 4.0.0, < 5.0)
63 | coffee-script (2.4.1)
64 | coffee-script-source
65 | execjs
66 | coffee-script-source (1.10.0)
67 | columnize (0.9.0)
68 | concurrent-ruby (1.0.0)
69 | debug_inspector (0.0.2)
70 | debugger-linecache (1.2.0)
71 | erubis (2.7.0)
72 | excon (0.46.0)
73 | execjs (2.6.0)
74 | faker (1.4.2)
75 | i18n (~> 0.5)
76 | ffi (1.9.10)
77 | fission (0.5.0)
78 | CFPropertyList (~> 2.2)
79 | fog (1.36.0)
80 | fog-aliyun (>= 0.1.0)
81 | fog-atmos
82 | fog-aws (>= 0.6.0)
83 | fog-brightbox (~> 0.4)
84 | fog-core (~> 1.32)
85 | fog-dynect (~> 0.0.2)
86 | fog-ecloud (~> 0.1)
87 | fog-google (<= 0.1.0)
88 | fog-json
89 | fog-local
90 | fog-powerdns (>= 0.1.1)
91 | fog-profitbricks
92 | fog-radosgw (>= 0.0.2)
93 | fog-riakcs
94 | fog-sakuracloud (>= 0.0.4)
95 | fog-serverlove
96 | fog-softlayer
97 | fog-storm_on_demand
98 | fog-terremark
99 | fog-vmfusion
100 | fog-voxel
101 | fog-xenserver
102 | fog-xml (~> 0.1.1)
103 | ipaddress (~> 0.5)
104 | nokogiri (~> 1.5, >= 1.5.11)
105 | fog-aliyun (0.1.0)
106 | fog-core (~> 1.27)
107 | fog-json (~> 1.0)
108 | ipaddress (~> 0.8)
109 | xml-simple (~> 1.1)
110 | fog-atmos (0.1.0)
111 | fog-core
112 | fog-xml
113 | fog-aws (0.8.1)
114 | fog-core (~> 1.27)
115 | fog-json (~> 1.0)
116 | fog-xml (~> 0.1)
117 | ipaddress (~> 0.8)
118 | fog-brightbox (0.10.1)
119 | fog-core (~> 1.22)
120 | fog-json
121 | inflecto (~> 0.0.2)
122 | fog-core (1.36.0)
123 | builder
124 | excon (~> 0.45)
125 | formatador (~> 0.2)
126 | fog-dynect (0.0.2)
127 | fog-core
128 | fog-json
129 | fog-xml
130 | fog-ecloud (0.3.0)
131 | fog-core
132 | fog-xml
133 | fog-google (0.1.0)
134 | fog-core
135 | fog-json
136 | fog-xml
137 | fog-json (1.0.2)
138 | fog-core (~> 1.0)
139 | multi_json (~> 1.10)
140 | fog-local (0.2.1)
141 | fog-core (~> 1.27)
142 | fog-powerdns (0.1.1)
143 | fog-core (~> 1.27)
144 | fog-json (~> 1.0)
145 | fog-xml (~> 0.1)
146 | fog-profitbricks (0.0.5)
147 | fog-core
148 | fog-xml
149 | nokogiri
150 | fog-radosgw (0.0.5)
151 | fog-core (>= 1.21.0)
152 | fog-json
153 | fog-xml (>= 0.0.1)
154 | fog-riakcs (0.1.0)
155 | fog-core
156 | fog-json
157 | fog-xml
158 | fog-sakuracloud (1.7.5)
159 | fog-core
160 | fog-json
161 | fog-serverlove (0.1.2)
162 | fog-core
163 | fog-json
164 | fog-softlayer (1.1.0)
165 | fog-core
166 | fog-json
167 | fog-storm_on_demand (0.1.1)
168 | fog-core
169 | fog-json
170 | fog-terremark (0.1.0)
171 | fog-core
172 | fog-xml
173 | fog-vmfusion (0.1.0)
174 | fission
175 | fog-core
176 | fog-voxel (0.1.0)
177 | fog-core
178 | fog-xml
179 | fog-xenserver (0.2.3)
180 | fog-core
181 | fog-xml
182 | fog-xml (0.1.2)
183 | fog-core
184 | nokogiri (~> 1.5, >= 1.5.11)
185 | formatador (0.2.5)
186 | globalid (0.3.6)
187 | activesupport (>= 4.1.0)
188 | guard (2.13.0)
189 | formatador (>= 0.2.4)
190 | listen (>= 2.7, <= 4.0)
191 | lumberjack (~> 1.0)
192 | nenv (~> 0.1)
193 | notiffany (~> 0.0)
194 | pry (>= 0.9.12)
195 | shellany (~> 0.0)
196 | thor (>= 0.18.1)
197 | guard-minitest (2.3.1)
198 | guard (~> 2.0)
199 | minitest (>= 3.0)
200 | i18n (0.7.0)
201 | inflecto (0.0.2)
202 | ipaddress (0.8.3)
203 | jbuilder (2.2.3)
204 | activesupport (>= 3.0.0, < 5)
205 | multi_json (~> 1.2)
206 | jquery-rails (4.0.3)
207 | rails-dom-testing (~> 1.0)
208 | railties (>= 4.2.0)
209 | thor (>= 0.14, < 2.0)
210 | json (1.8.3)
211 | listen (3.0.6)
212 | rb-fsevent (>= 0.9.3)
213 | rb-inotify (>= 0.9.7)
214 | loofah (2.0.3)
215 | nokogiri (>= 1.5.9)
216 | lumberjack (1.0.10)
217 | mail (2.6.3)
218 | mime-types (>= 1.16, < 3)
219 | method_source (0.8.2)
220 | mime-types (2.99)
221 | mini_backtrace (0.1.3)
222 | minitest (> 1.2.0)
223 | rails (>= 2.3.3)
224 | mini_magick (3.8.0)
225 | subexec (~> 0.2.1)
226 | mini_portile2 (2.0.0)
227 | minitest (5.8.4)
228 | minitest-reporters (1.0.5)
229 | ansi
230 | builder
231 | minitest (>= 5.0)
232 | ruby-progressbar
233 | multi_json (1.11.2)
234 | nenv (0.3.0)
235 | nokogiri (1.6.7.2)
236 | mini_portile2 (~> 2.0.0.rc2)
237 | notiffany (0.0.8)
238 | nenv (~> 0.1)
239 | shellany (~> 0.0)
240 | pg (0.17.1)
241 | pry (0.10.3)
242 | coderay (~> 1.1.0)
243 | method_source (~> 0.8.1)
244 | slop (~> 3.4)
245 | puma (2.11.1)
246 | rack (>= 1.1, < 2.0)
247 | rack (1.6.4)
248 | rack-test (0.6.3)
249 | rack (>= 1.0)
250 | rails (4.2.2)
251 | actionmailer (= 4.2.2)
252 | actionpack (= 4.2.2)
253 | actionview (= 4.2.2)
254 | activejob (= 4.2.2)
255 | activemodel (= 4.2.2)
256 | activerecord (= 4.2.2)
257 | activesupport (= 4.2.2)
258 | bundler (>= 1.3.0, < 2.0)
259 | railties (= 4.2.2)
260 | sprockets-rails
261 | rails-deprecated_sanitizer (1.0.3)
262 | activesupport (>= 4.2.0.alpha)
263 | rails-dom-testing (1.0.7)
264 | activesupport (>= 4.2.0.beta, < 5.0)
265 | nokogiri (~> 1.6.0)
266 | rails-deprecated_sanitizer (>= 1.0.1)
267 | rails-html-sanitizer (1.0.3)
268 | loofah (~> 2.0)
269 | rails_12factor (0.0.2)
270 | rails_serve_static_assets
271 | rails_stdout_logging
272 | rails_serve_static_assets (0.0.5)
273 | rails_stdout_logging (0.0.4)
274 | railties (4.2.2)
275 | actionpack (= 4.2.2)
276 | activesupport (= 4.2.2)
277 | rake (>= 0.8.7)
278 | thor (>= 0.18.1, < 2.0)
279 | rake (10.5.0)
280 | rb-fsevent (0.9.7)
281 | rb-inotify (0.9.7)
282 | ffi (>= 0.5.0)
283 | rdoc (4.2.2)
284 | json (~> 1.4)
285 | ruby-progressbar (1.7.5)
286 | sass (3.4.21)
287 | sass-rails (5.0.2)
288 | railties (>= 4.0.0, < 5.0)
289 | sass (~> 3.1)
290 | sprockets (>= 2.8, < 4.0)
291 | sprockets-rails (>= 2.0, < 4.0)
292 | tilt (~> 1.1)
293 | sdoc (0.4.0)
294 | json (~> 1.8)
295 | rdoc (~> 4.0, < 5.0)
296 | shellany (0.0.1)
297 | slop (3.6.0)
298 | spring (1.1.3)
299 | sprockets (3.5.2)
300 | concurrent-ruby (~> 1.0)
301 | rack (> 1, < 3)
302 | sprockets-rails (3.0.1)
303 | actionpack (>= 4.0)
304 | activesupport (>= 4.0)
305 | sprockets (>= 3.0.0)
306 | sqlite3 (1.3.9)
307 | subexec (0.2.3)
308 | thor (0.19.1)
309 | thread_safe (0.3.5)
310 | tilt (1.4.1)
311 | turbolinks (2.3.0)
312 | coffee-rails
313 | tzinfo (1.2.2)
314 | thread_safe (~> 0.1)
315 | uglifier (2.5.3)
316 | execjs (>= 0.3.0)
317 | json (>= 1.8.0)
318 | web-console (2.0.0.beta3)
319 | activemodel (~> 4.0)
320 | binding_of_caller (= 0.7.3.pre1)
321 | railties (~> 4.0)
322 | sprockets-rails (>= 2.0, < 4.0)
323 | will_paginate (3.0.7)
324 | xml-simple (1.1.5)
325 |
326 | PLATFORMS
327 | ruby
328 |
329 | DEPENDENCIES
330 | bcrypt (= 3.1.7)
331 | bootstrap-sass (= 3.2.0.0)
332 | bootstrap-will_paginate (= 0.0.10)
333 | byebug (= 3.4.0)
334 | carrierwave (= 0.10.0)
335 | coffee-rails (= 4.1.0)
336 | faker (= 1.4.2)
337 | fog (= 1.36.0)
338 | guard-minitest (= 2.3.1)
339 | jbuilder (= 2.2.3)
340 | jquery-rails (= 4.0.3)
341 | mini_backtrace (= 0.1.3)
342 | mini_magick (= 3.8.0)
343 | minitest-reporters (= 1.0.5)
344 | pg (= 0.17.1)
345 | puma (= 2.11.1)
346 | rails (= 4.2.2)
347 | rails_12factor (= 0.0.2)
348 | sass-rails (= 5.0.2)
349 | sdoc (= 0.4.0)
350 | spring (= 1.1.3)
351 | sqlite3 (= 1.3.9)
352 | turbolinks (= 2.3.0)
353 | uglifier (= 2.5.3)
354 | web-console (= 2.0.0.beta3)
355 | will_paginate (= 3.0.7)
356 |
--------------------------------------------------------------------------------