tft_rails_dbc 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/.rvmrc +1 -0
- data/Gemfile +8 -0
- data/LICENSE +57 -0
- data/README.md +90 -0
- data/Rakefile +25 -0
- data/lib/generators/chapter07/begin/USAGE +27 -0
- data/lib/generators/chapter07/begin/begin_generator.rb +39 -0
- data/lib/generators/chapter07/begin/instructions.md +74 -0
- data/lib/generators/chapter07/begin/templates/app/controllers/application_controller.rb +8 -0
- data/lib/generators/chapter07/begin/templates/app/controllers/pages_controller.rb +11 -0
- data/lib/generators/chapter07/begin/templates/app/controllers/users_controller.rb +3 -0
- data/lib/generators/chapter07/begin/templates/app/helpers/application_helper.rb +12 -0
- data/lib/generators/chapter07/begin/templates/app/helpers/pages_helper.rb +2 -0
- data/lib/generators/chapter07/begin/templates/app/helpers/users_helper.rb +7 -0
- data/lib/generators/chapter07/begin/templates/app/models/user.rb +9 -0
- data/lib/generators/chapter07/begin/templates/app/views/layouts/_footer.html.erb +9 -0
- data/lib/generators/chapter07/begin/templates/app/views/layouts/_header.html.erb +10 -0
- data/lib/generators/chapter07/begin/templates/app/views/layouts/_stylesheets.html.erb +7 -0
- data/lib/generators/chapter07/begin/templates/app/views/layouts/application.html.erb +17 -0
- data/lib/generators/chapter07/begin/templates/app/views/pages/about.html.erb +7 -0
- data/lib/generators/chapter07/begin/templates/app/views/pages/contact.html.erb +5 -0
- data/lib/generators/chapter07/begin/templates/app/views/pages/home.html.erb +7 -0
- data/lib/generators/chapter07/begin/templates/app/views/users/show.html.erb +15 -0
- data/lib/generators/chapter07/begin/templates/config/initializers/devise.rb +194 -0
- data/lib/generators/chapter07/begin/templates/config/locales/devise.en.yml +50 -0
- data/lib/generators/chapter07/begin/templates/config/routes.rb.tt +17 -0
- data/lib/generators/chapter07/begin/templates/db/migrate/20110608224650_devise_create_users.rb +29 -0
- data/lib/generators/chapter07/begin/templates/db/schema.rb +34 -0
- data/lib/generators/chapter07/begin/templates/public/images/logo.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/ie.css +36 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/buttons/icons/cross.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/buttons/icons/key.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/buttons/icons/tick.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/buttons/readme.txt +32 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/buttons/screen.css +97 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/fancy-type/readme.txt +14 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/fancy-type/screen.css +71 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/link-icons/icons/doc.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/link-icons/icons/email.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/link-icons/icons/external.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/link-icons/icons/feed.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/link-icons/icons/im.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/link-icons/icons/lock.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/link-icons/icons/pdf.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/link-icons/icons/visited.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/link-icons/icons/xls.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/link-icons/readme.txt +18 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/link-icons/screen.css +42 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/rtl/readme.txt +10 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/plugins/rtl/screen.css +110 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/print.css +29 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/screen.css +265 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/src/forms.css +82 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/src/grid.css +280 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/src/grid.png +0 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/src/ie.css +79 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/src/print.css +92 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/src/reset.css +65 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/blueprint/src/typography.css +123 -0
- data/lib/generators/chapter07/begin/templates/public/stylesheets/custom.css +137 -0
- data/lib/generators/chapter07/begin/templates/spec/controllers/pages_controller_07_spec.rb +48 -0
- data/lib/generators/chapter07/begin/templates/spec/controllers/users_controller_07_spec.rb +38 -0
- data/lib/generators/chapter07/begin/templates/spec/factories.rb +9 -0
- data/lib/generators/chapter07/begin/templates/spec/models/user_07_spec.rb +38 -0
- data/lib/generators/chapter07/begin/templates/spec/requests/layout_links_07_spec.rb +44 -0
- data/lib/generators/chapter07/begin/templates/spec/spec_helper.rb +39 -0
- data/lib/generators/chapter07/solutions/USAGE +21 -0
- data/lib/generators/chapter07/solutions/solutions_generator.rb +23 -0
- data/lib/generators/chapter07/solutions/templates/app/controllers/pages_controller.rb +18 -0
- data/lib/generators/chapter07/solutions/templates/app/controllers/users_controller.rb +8 -0
- data/lib/generators/chapter07/solutions/templates/app/models/user.rb +11 -0
- data/lib/generators/chapter07/solutions/templates/app/views/layouts/_footer.html.erb +10 -0
- data/lib/generators/chapter07/solutions/templates/app/views/layouts/_header.html.erb +11 -0
- data/lib/generators/chapter07/solutions/templates/app/views/pages/help.html.erb +4 -0
- data/lib/generators/chapter07/solutions/templates/app/views/pages/home.html.erb +7 -0
- data/lib/generators/chapter07/solutions/templates/app/views/users/show.html.erb +15 -0
- data/lib/generators/chapter08_09/begin/USAGE +24 -0
- data/lib/generators/chapter08_09/begin/begin_generator.rb +29 -0
- data/lib/generators/chapter08_09/begin/instructions.md +65 -0
- data/lib/generators/chapter08_09/begin/snippets/custom.css +49 -0
- data/lib/generators/chapter08_09/begin/templates/spec/controllers/devise/registrations_controller_08_spec.rb +83 -0
- data/lib/generators/chapter08_09/begin/templates/spec/requests/layout_links_09_spec.rb +35 -0
- data/lib/generators/chapter08_09/begin/templates/spec/requests/users_signup_08_spec.rb +36 -0
- data/lib/generators/chapter08_09/solutions/USAGE +18 -0
- data/lib/generators/chapter08_09/solutions/solutions_generator.rb +12 -0
- data/lib/generators/chapter08_09/solutions/templates/app/helpers/application_helper.rb +16 -0
- data/lib/generators/chapter08_09/solutions/templates/app/views/devise/passwords/edit.html.erb +16 -0
- data/lib/generators/chapter08_09/solutions/templates/app/views/devise/passwords/new.html.erb +12 -0
- data/lib/generators/chapter08_09/solutions/templates/app/views/devise/registrations/_fields.html.erb +16 -0
- data/lib/generators/chapter08_09/solutions/templates/app/views/devise/registrations/edit.html.erb +28 -0
- data/lib/generators/chapter08_09/solutions/templates/app/views/devise/registrations/new.html.erb +13 -0
- data/lib/generators/chapter08_09/solutions/templates/app/views/devise/sessions/new.html.erb +17 -0
- data/lib/generators/chapter08_09/solutions/templates/app/views/devise/shared/_links.erb +25 -0
- data/lib/generators/chapter08_09/solutions/templates/app/views/layouts/_header.html.erb +19 -0
- data/lib/generators/chapter08_09/solutions/templates/app/views/layouts/application.html.erb +20 -0
- data/lib/generators/chapter10/begin/USAGE +24 -0
- data/lib/generators/chapter10/begin/begin_generator.rb +41 -0
- data/lib/generators/chapter10/begin/instructions.md +47 -0
- data/lib/generators/chapter10/begin/snippets/custom.css +12 -0
- data/lib/generators/chapter10/begin/snippets/factories.rb +10 -0
- data/lib/generators/chapter10/begin/templates/app/views/layouts/application.html.erb +21 -0
- data/lib/generators/chapter10/begin/templates/lib/tasks/sample_data.rake +24 -0
- data/lib/generators/chapter10/begin/templates/spec/controllers/users_controller_10_spec.rb +110 -0
- data/lib/generators/chapter10/begin/templates/spec/models/user_10_spec.rb +24 -0
- data/lib/generators/chapter10/solutions/USAGE +18 -0
- data/lib/generators/chapter10/solutions/snippets/migration_add_admin_to_users.rb +9 -0
- data/lib/generators/chapter10/solutions/solutions_generator.rb +32 -0
- data/lib/generators/chapter10/solutions/templates/app/controllers/users_controller.rb +28 -0
- data/lib/generators/chapter10/solutions/templates/app/views/users/_user.html.erb +8 -0
- data/lib/generators/chapter10/solutions/templates/app/views/users/index.html.erb +9 -0
- data/lib/generators/chapter11_1/begin/USAGE +24 -0
- data/lib/generators/chapter11_1/begin/begin_generator.rb +24 -0
- data/lib/generators/chapter11_1/begin/instructions.md +39 -0
- data/lib/generators/chapter11_1/begin/templates/lib/tasks/sample_data.rake +29 -0
- data/lib/generators/chapter11_1/begin/templates/spec/models/microposts_11_1_spec.rb +45 -0
- data/lib/generators/chapter11_1/begin/templates/spec/models/user_11_1_spec.rb +30 -0
- data/lib/generators/chapter11_1/solutions/USAGE +18 -0
- data/lib/generators/chapter11_1/solutions/snippets/migration_create_microposts.rb +17 -0
- data/lib/generators/chapter11_1/solutions/solutions_generator.rb +25 -0
- data/lib/generators/chapter11_1/solutions/templates/app/models/micropost.rb +10 -0
- data/lib/generators/chapter11_1/solutions/templates/app/models/user.rb +14 -0
- data/lib/generators/chapter11_1/solutions/templates/spec/factories.rb +16 -0
- data/lib/generators/chapter11_2/begin/USAGE +24 -0
- data/lib/generators/chapter11_2/begin/begin_generator.rb +30 -0
- data/lib/generators/chapter11_2/begin/instructions.md +35 -0
- data/lib/generators/chapter11_2/begin/snippets/custom.css +59 -0
- data/lib/generators/chapter11_2/begin/templates/app/views/users/show.html.erb +23 -0
- data/lib/generators/chapter11_2/begin/templates/spec/controllers/users_controller_11_2_spec.rb +31 -0
- data/lib/generators/chapter11_2/solutions/USAGE +18 -0
- data/lib/generators/chapter11_2/solutions/solutions_generator.rb +12 -0
- data/lib/generators/chapter11_2/solutions/templates/app/controllers/users_controller.rb +29 -0
- data/lib/generators/chapter11_2/solutions/templates/app/views/microposts/_micropost.html.erb +8 -0
- data/lib/generators/chapter11_2/solutions/templates/app/views/users/show.html.erb +23 -0
- data/lib/generators/chapter11_3/begin/USAGE +24 -0
- data/lib/generators/chapter11_3/begin/begin_generator.rb +24 -0
- data/lib/generators/chapter11_3/begin/instructions.md +80 -0
- data/lib/generators/chapter11_3/begin/templates/app/views/pages/home.html.erb +24 -0
- data/lib/generators/chapter11_3/begin/templates/app/views/shared/_feed.html.erb +6 -0
- data/lib/generators/chapter11_3/begin/templates/app/views/shared/_feed_item.html.erb +14 -0
- data/lib/generators/chapter11_3/begin/templates/app/views/shared/_micropost_form.html.erb +9 -0
- data/lib/generators/chapter11_3/begin/templates/app/views/shared/_user_info.html.erb +11 -0
- data/lib/generators/chapter11_3/begin/templates/spec/controllers/microposts_controllers_11_3_spec.rb +103 -0
- data/lib/generators/chapter11_3/begin/templates/spec/controllers/pages_controller_11_3_spec.rb +14 -0
- data/lib/generators/chapter11_3/begin/templates/spec/models/user_11_3_spec.rb +31 -0
- data/lib/generators/chapter11_3/begin/templates/spec/requests/micropost_11_3_spec.rb +41 -0
- data/lib/generators/chapter11_3/solutions/USAGE +18 -0
- data/lib/generators/chapter11_3/solutions/solutions_generator.rb +30 -0
- data/lib/generators/chapter11_3/solutions/templates/app/controllers/microposts_controller.rb +20 -0
- data/lib/generators/chapter11_3/solutions/templates/app/controllers/pages_controller.rb +22 -0
- data/lib/generators/chapter11_3/solutions/templates/app/views/microposts/_micropost.html.erb +15 -0
- data/lib/generators/chapter11_3/solutions/templates/app/views/pages/home.html.erb +24 -0
- data/lib/generators/chapter11_3/solutions/templates/app/views/shared/_error_messages.html.erb +13 -0
- data/lib/generators/chapter11_3/solutions/templates/app/views/shared/_feed.html.erb +6 -0
- data/lib/generators/chapter11_3/solutions/templates/app/views/shared/_feed_item.html.erb +21 -0
- data/lib/generators/chapter11_3/solutions/templates/app/views/shared/_micropost_form.html.erb +9 -0
- data/lib/generators/chapter11_3/solutions/templates/app/views/shared/_user_info.html.erb +11 -0
- data/lib/tft_rails.rb +2 -0
- metadata +217 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe UsersController do
|
4
|
+
render_views
|
5
|
+
|
6
|
+
describe "GET 'index'" do
|
7
|
+
|
8
|
+
describe "for non-signed-in users" do
|
9
|
+
it "should deny access" do
|
10
|
+
get :index
|
11
|
+
response.should redirect_to(new_user_session_path)
|
12
|
+
flash[:alert].should =~ /sign in/i
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "for signed-in users" do
|
17
|
+
|
18
|
+
before(:each) do
|
19
|
+
@user = Factory(:user)
|
20
|
+
sign_in(@user)
|
21
|
+
|
22
|
+
second = Factory(:user, :name => "Bob", :email => "another@example.com")
|
23
|
+
third = Factory(:user, :name => "Ben", :email => "another@example.net")
|
24
|
+
|
25
|
+
@users = [@user, second, third]
|
26
|
+
@users = [@user, second, third]
|
27
|
+
30.times do
|
28
|
+
@users << Factory(:user, :email => Factory.next(:email))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should be successful" do
|
33
|
+
get :index
|
34
|
+
response.should be_success
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should have the right title" do
|
38
|
+
get :index
|
39
|
+
response.should render_template('index')
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should have an element for each user" do
|
43
|
+
get :index
|
44
|
+
@users[0..2].each do |user|
|
45
|
+
response.should have_selector("li", :content => user.name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should paginate users" do
|
50
|
+
get :index
|
51
|
+
response.should have_selector("div.pagination")
|
52
|
+
response.should have_selector("span.disabled", :content => "Previous")
|
53
|
+
response.should have_selector("a", :href => "/users?page=2",
|
54
|
+
:content => "2")
|
55
|
+
response.should have_selector("a", :href => "/users?page=2",
|
56
|
+
:content => "Next")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "DELETE 'destroy'" do
|
62
|
+
|
63
|
+
before(:each) do
|
64
|
+
@user = Factory(:user)
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "as a non-signed-in user" do
|
68
|
+
it "should deny access" do
|
69
|
+
delete :destroy, :id => @user
|
70
|
+
response.should redirect_to(new_user_session_path)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "as a non-admin user" do
|
75
|
+
before do
|
76
|
+
sign_in(@user)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should protect the page" do
|
80
|
+
delete :destroy, :id => @user
|
81
|
+
response.should redirect_to(root_path)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should not destroy the user' do
|
85
|
+
expect {
|
86
|
+
delete :destroy, :id => @user
|
87
|
+
}.to_not change(User,:count)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "as an admin user" do
|
92
|
+
|
93
|
+
before(:each) do
|
94
|
+
admin = Factory(:user, :email => "admin@example.com", :admin => true)
|
95
|
+
sign_in(admin)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should destroy the user" do
|
99
|
+
expect {
|
100
|
+
delete :destroy, :id => @user
|
101
|
+
}.to change(User, :count).by(-1)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should redirect to the users page" do
|
105
|
+
delete :destroy, :id => @user
|
106
|
+
response.should redirect_to(users_path)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe User do
|
4
|
+
|
5
|
+
describe "admin attribute" do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@user = Factory(:user)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should respond to admin" do
|
12
|
+
@user.should respond_to(:admin)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should not be an admin by default" do
|
16
|
+
@user.should_not be_admin
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should be convertible to an admin" do
|
20
|
+
@user.toggle!(:admin)
|
21
|
+
@user.should be_admin
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Description:
|
2
|
+
Wraps up Test-First Teaching exercises adapted from Chapter 10 of the RailsTutorial by Michael Hartl.
|
3
|
+
|
4
|
+
Example:
|
5
|
+
rails generate chapter10:solutions
|
6
|
+
|
7
|
+
This copies the solutions and other necessary files (e.g. images, assets, helpers, etc.) into the project
|
8
|
+
to conclude Chapter 10. This should make all tests pass and bring you in sync to the application at
|
9
|
+
the end of Chapter 10.
|
10
|
+
|
11
|
+
If you already have a solution file, you'll be prompted whether you want to overwrite your file,
|
12
|
+
see the difference, or keep your file.
|
13
|
+
|
14
|
+
It's a good idea to commit your changes to git, prior to running finish, in case you accidentally choose to
|
15
|
+
overwrite files you wanted to keep. Assuming your project is already git-controlled, you can commit changes with:
|
16
|
+
|
17
|
+
git add .
|
18
|
+
git commit -m "comment here explaining WHY you made the changes"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Chapter10
|
2
|
+
module Generators
|
3
|
+
class SolutionsGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
def copy_app_tree
|
7
|
+
directory(self.class.source_root, Rails.root)
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_destroy_action_to_users_resource
|
11
|
+
dest = File.join(Rails.root,'config','routes.rb')
|
12
|
+
insert_into_file(dest, :after => %r{:index,\s*:show}) do
|
13
|
+
", :destroy"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_migration
|
18
|
+
found_candidate = Dir.glob(File.join(Rails.root,'db','migrate','*_admin_*')).present?
|
19
|
+
|
20
|
+
if (found_candidate &&
|
21
|
+
yes?("We found a migration file containing the word '_admin_'. We think you have the correct migration. Do you still way to copy the solution anyway? (yes/no)", :yellow)) \
|
22
|
+
or !found_candidate
|
23
|
+
|
24
|
+
src = File.expand_path("../snippets/migration_add_admin_to_users.rb", __FILE__)
|
25
|
+
dest = File.join(Rails.root,'db','migrate',Time.now.strftime("%Y%m%d%H%M%S")+'_add_admin_to_users.rb')
|
26
|
+
copy_file(src,dest)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class UsersController < ApplicationController
|
2
|
+
|
3
|
+
before_filter :authenticate_user!, :only => [:index, :destroy]
|
4
|
+
before_filter :admin_user, :only => :destroy
|
5
|
+
|
6
|
+
def show
|
7
|
+
@user = User.find(params[:id])
|
8
|
+
@title = @user.name
|
9
|
+
end
|
10
|
+
|
11
|
+
def index
|
12
|
+
@title = "All users"
|
13
|
+
@users = User.paginate(:page => params[:page])
|
14
|
+
end
|
15
|
+
|
16
|
+
def destroy
|
17
|
+
User.find(params[:id]).destroy
|
18
|
+
flash[:notice] = "User destroyed."
|
19
|
+
redirect_to users_path
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def admin_user
|
25
|
+
redirect_to(root_path) unless current_user.admin?
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Description:
|
2
|
+
Begins Test-First Teaching exercises adapted from Chapter 11.1 of the RailsTutorial by Michael Hartl.
|
3
|
+
|
4
|
+
It is assumed that this generator is run after the exercises for all prior chapters have been completed, and the solutions are implemented.
|
5
|
+
|
6
|
+
Successive chapters are expected to be run sequentially. Each chapter's generators comes with a delta
|
7
|
+
to the next chapter, in two phase, the "begin" one will create tests, the "finish" one includes the solution files.
|
8
|
+
If all tests pass, the "finish" phase is optional.
|
9
|
+
|
10
|
+
Example:
|
11
|
+
rails generate chapter11_1:begin
|
12
|
+
|
13
|
+
This copies new tests into the project, which are failing.
|
14
|
+
The student's task is to write code to make the test pass. The material covered by the tests is consistent
|
15
|
+
with Chapter 11.1 of the RailsTutorial, however adapted for Devise as authentication solution.
|
16
|
+
|
17
|
+
When you're done, and all tests pass, or you just want to skip ahead, run:
|
18
|
+
|
19
|
+
rails generate chapter11_1:solutions
|
20
|
+
|
21
|
+
This will copy solutions files into the application tree. If you already have a solution file,
|
22
|
+
you'll be prompted whether you want to overwrite your file, see the difference, or keep your file.
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Chapter11_1
|
2
|
+
module Generators
|
3
|
+
class BeginGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
def copy_app_tree
|
7
|
+
directory(self.class.source_root, Rails.root)
|
8
|
+
end
|
9
|
+
|
10
|
+
def generate_instructions
|
11
|
+
require 'rdiscount'
|
12
|
+
|
13
|
+
instr_md = File.expand_path('../instructions.md',self.class.source_root)
|
14
|
+
return unless File.exists?(instr_md)
|
15
|
+
dest = File.join(Rails.root,'doc','chapter11_1.html')
|
16
|
+
copy_file(instr_md, dest, :force => true) do |content|
|
17
|
+
RDiscount.new(content).to_html
|
18
|
+
end
|
19
|
+
say_status('Note',"Now open file://#{dest} in your web browser for instructions", :cyan)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
RailsTutorial Chapter 11.1 Test-First Teaching Instructions
|
2
|
+
=========================================================
|
3
|
+
|
4
|
+
Chapter 11.1 covers adding a Micropost model and setting up an association between
|
5
|
+
User and Micropost.
|
6
|
+
|
7
|
+
When you first run `rake spec`, you'll get an error like below and no specs will execute.
|
8
|
+
|
9
|
+
uninitialized constant Micropost (NameError)
|
10
|
+
|
11
|
+
This is because we don't have this class defined yet. So, go ahead and create it using the rails generators:
|
12
|
+
|
13
|
+
rails generate model Micropost content:string user_id:integer
|
14
|
+
|
15
|
+
This will generate a migration file, a model file and a spec file for Micropost. Note that for the TFT
|
16
|
+
exercises, a spec file is already provided, and we don't need the generated spec file. So, go ahead
|
17
|
+
and _remove:_ `spec/models/micropost_spec.rb`
|
18
|
+
|
19
|
+
Add indexes to the migration file, see [Chapter 11.1.1][chapter_11_1_1]. Indices should be added for each
|
20
|
+
column that will be used for record lookup or ordering. For instance, if we want to sort Microposts by
|
21
|
+
creation date, then there should be an index on the `created_at` column. (Note that the `timestamps` migration
|
22
|
+
methods created two columns, `created_at` and `updated_at`.)
|
23
|
+
|
24
|
+
Then migrate the database:
|
25
|
+
|
26
|
+
rake db:migrate
|
27
|
+
|
28
|
+
|
29
|
+
Rails Concepts Covered
|
30
|
+
======================
|
31
|
+
|
32
|
+
* Using the model generator (for Microposts)
|
33
|
+
* Adding indexes to the database
|
34
|
+
* Associations, has_many (dep't destroy) and belongs_to
|
35
|
+
* Validations for format
|
36
|
+
* Factories with associations
|
37
|
+
* Scopes (simple, default scope), order
|
38
|
+
|
39
|
+
[chapter_11_1_1]: http://ruby.railstutorial.org/chapters/user-microposts#sec:the_basic_model "RailsTutorial Chapter 11.1.1"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
namespace :db do
|
2
|
+
desc "Fill database with sample data"
|
3
|
+
task :populate => :environment do
|
4
|
+
Rake::Task['db:reset'].invoke
|
5
|
+
make_users
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def make_users
|
10
|
+
admin = User.create!(:name => "Example User",
|
11
|
+
:email => "example@railstutorial.org",
|
12
|
+
:password => "password",
|
13
|
+
:password_confirmation => "password")
|
14
|
+
admin.toggle!(:admin)
|
15
|
+
99.times do |n|
|
16
|
+
name = Faker::Name.name
|
17
|
+
email = "example-#{n+1}@railstutorial.org"
|
18
|
+
password = "password"
|
19
|
+
User.create!(:name => name,
|
20
|
+
:email => email,
|
21
|
+
:password => password,
|
22
|
+
:password_confirmation => password)
|
23
|
+
end
|
24
|
+
User.all(:limit => 6).each do |user|
|
25
|
+
50.times do
|
26
|
+
user.microposts.create!(:content => Faker::Lorem.sentence(5))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Micropost do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@user = Factory(:user)
|
7
|
+
@attr = { :content => "value for content" }
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should create a new instance given valid attributes" do
|
11
|
+
@user.microposts.create!(@attr)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "user associations" do
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
@micropost = @user.microposts.create(@attr)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have a user attribute" do
|
21
|
+
@micropost.should respond_to(:user)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should have the right associated user" do
|
25
|
+
@micropost.user_id.should == @user.id
|
26
|
+
@micropost.user.should == @user
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "validations" do
|
31
|
+
|
32
|
+
it "should require a user id" do
|
33
|
+
Micropost.new(@attr).should_not be_valid
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should require nonblank content" do
|
37
|
+
@user.microposts.build(:content => " ").should_not be_valid
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should reject long content" do
|
41
|
+
@user.microposts.build(:content => "a" * 141).should_not be_valid
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe User do
|
4
|
+
|
5
|
+
describe "micropost associations" do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@user = Factory(:user)
|
9
|
+
@mp1 = Factory(:micropost, :user => @user, :created_at => 1.day.ago)
|
10
|
+
@mp2 = Factory(:micropost, :user => @user, :created_at => 1.hour.ago)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have a microposts attribute" do
|
14
|
+
@user.should respond_to(:microposts)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have the right microposts in the right order" do
|
18
|
+
@user.microposts.should == [@mp2, @mp1]
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should destroy associated microposts" do
|
22
|
+
@user.destroy
|
23
|
+
[@mp1, @mp2].each do |micropost|
|
24
|
+
Micropost.find_by_id(micropost.id).should be_nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Description:
|
2
|
+
Wraps up Test-First Teaching exercises adapted from Chapter 11.1 of the RailsTutorial by Michael Hartl.
|
3
|
+
|
4
|
+
Example:
|
5
|
+
rails generate chapter11:solutions
|
6
|
+
|
7
|
+
This copies the solutions and other necessary files (e.g. images, assets, helpers, etc.) into the project
|
8
|
+
to conclude Chapter 11.1. This should make all tests pass and bring you in sync to the application at
|
9
|
+
the end of Chapter 11.1.
|
10
|
+
|
11
|
+
If you already have a solution file, you'll be prompted whether you want to overwrite your file,
|
12
|
+
see the difference, or keep your file.
|
13
|
+
|
14
|
+
It's a good idea to commit your changes to git, prior to running finish, in case you accidentally choose to
|
15
|
+
overwrite files you wanted to keep. Assuming your project is already git-controlled, you can commit changes with:
|
16
|
+
|
17
|
+
git add .
|
18
|
+
git commit -m "comment here explaining WHY you made the changes"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class CreateMicroposts < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :microposts do |t|
|
4
|
+
t.string :content
|
5
|
+
t.integer :user_id
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
add_index :microposts, :user_id
|
11
|
+
add_index :microposts, :created_at
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.down
|
15
|
+
drop_table :microposts
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Chapter11_1
|
2
|
+
module Generators
|
3
|
+
class SolutionsGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
def copy_app_tree
|
7
|
+
directory(self.class.source_root, Rails.root)
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_migration
|
11
|
+
found_candidate = Dir.glob(File.join(Rails.root,'db','migrate','*create_micropost*')).present?
|
12
|
+
|
13
|
+
if (found_candidate &&
|
14
|
+
yes?("We found a migration file containing the word '_admin_'. We think you have the correct migration. Do you still way to copy the solution anyway? (yes/no)", :yellow)) \
|
15
|
+
or !found_candidate
|
16
|
+
|
17
|
+
src = File.expand_path("../snippets/migration_create_microposts.rb", __FILE__)
|
18
|
+
dest = File.join(Rails.root,'db','migrate',Time.now.strftime("%Y%m%d%H%M%S")+'_create_microposts.rb')
|
19
|
+
copy_file(src,dest)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class User < ActiveRecord::Base
|
2
|
+
# Include default devise modules. Others available are:
|
3
|
+
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
|
4
|
+
devise :database_authenticatable, :registerable,
|
5
|
+
:recoverable, :rememberable, :trackable, :validatable
|
6
|
+
|
7
|
+
validates :name, :presence => true, :length => { :maximum => 50 }
|
8
|
+
|
9
|
+
# Setup accessible (or protected) attributes for your model
|
10
|
+
attr_accessible :name, :email, :password, :password_confirmation, :remember_me
|
11
|
+
|
12
|
+
has_many :microposts, :dependent => :destroy
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# By using the symbol ':user', we get Factory Girl to simulate the User model.
|
2
|
+
Factory.define :user do |user|
|
3
|
+
user.name "Michael Hartl"
|
4
|
+
user.email "mhartl@example.com"
|
5
|
+
user.password "foobar"
|
6
|
+
user.password_confirmation "foobar"
|
7
|
+
end
|
8
|
+
|
9
|
+
Factory.sequence :email do |n|
|
10
|
+
"person-#{n}@example.com"
|
11
|
+
end
|
12
|
+
|
13
|
+
Factory.define :micropost do |mp|
|
14
|
+
mp.content "This is a new post"
|
15
|
+
mp.association :user
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Description:
|
2
|
+
Begins Test-First Teaching exercises adapted from Chapter 11.2 of the RailsTutorial by Michael Hartl.
|
3
|
+
|
4
|
+
It is assumed that this generator is run after the exercises for all prior chapters have been completed, and the solutions are implemented.
|
5
|
+
|
6
|
+
Successive chapters are expected to be run sequentially. Each chapter's generators comes with a delta
|
7
|
+
to the next chapter, in two phase, the "begin" one will create tests, the "finish" one includes the solution files.
|
8
|
+
If all tests pass, the "finish" phase is optional.
|
9
|
+
|
10
|
+
Example:
|
11
|
+
rails generate chapter11_2:begin
|
12
|
+
|
13
|
+
This copies new tests into the project, which are failing.
|
14
|
+
The student's task is to write code to make the test pass. The material covered by the tests is consistent
|
15
|
+
with Chapter 11.2 of the RailsTutorial, however adapted for Devise as authentication solution.
|
16
|
+
|
17
|
+
When you're done, and all tests pass, or you just want to skip ahead, run:
|
18
|
+
|
19
|
+
rails generate chapter11_2:solutions
|
20
|
+
|
21
|
+
This will copy solutions files into the application tree. If you already have a solution file,
|
22
|
+
you'll be prompted whether you want to overwrite your file, see the difference, or keep your file.
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Chapter11_2
|
2
|
+
module Generators
|
3
|
+
class BeginGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
def copy_app_tree
|
7
|
+
directory(self.class.source_root, Rails.root)
|
8
|
+
end
|
9
|
+
|
10
|
+
def insert_css
|
11
|
+
src = File.expand_path("../snippets/custom.css", __FILE__)
|
12
|
+
dest = File.join(Rails.root,'public','stylesheets','custom.css')
|
13
|
+
insert_into_file(dest, File.binread(src), :before => /\Z/) # insert before end
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate_instructions
|
17
|
+
require 'rdiscount'
|
18
|
+
|
19
|
+
instr_md = File.expand_path('../instructions.md',self.class.source_root)
|
20
|
+
return unless File.exists?(instr_md)
|
21
|
+
dest = File.join(Rails.root,'doc','chapter11_2.html')
|
22
|
+
copy_file(instr_md, dest, :force => true) do |content|
|
23
|
+
RDiscount.new(content).to_html
|
24
|
+
end
|
25
|
+
say_status('Note',"Now open file://#{dest} in your web browser for instructions", :cyan)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
RailsTutorial Chapter 11.2 Test-First Teaching Instructions
|
2
|
+
===========================================================
|
3
|
+
|
4
|
+
When you first run `rake spec`, you'll get an error like below and no specs will execute.
|
5
|
+
|
6
|
+
uninitialized constant MicropostsController (NameError)
|
7
|
+
|
8
|
+
This is because we don't have this class defined yet. So, go ahead and create it using the rails generators:
|
9
|
+
|
10
|
+
_Note_: **Microposts is in plural here** (Rails convention for controllers).
|
11
|
+
|
12
|
+
rails g controller Microposts --controller-specs=false --view-specs=false --helper-specs=false
|
13
|
+
|
14
|
+
Note: The controller generatore (unlike the model generator), we can instruct to suppress
|
15
|
+
the spec files.
|
16
|
+
|
17
|
+
For the particular markup to make the micropost display look pretty,
|
18
|
+
refer to Rails Tutorial [Chapter 11.2.1][chapter_11_2_1]
|
19
|
+
|
20
|
+
Extra Credit
|
21
|
+
------------
|
22
|
+
|
23
|
+
Review how pagination for the users index page was done in Chapter 10.
|
24
|
+
Apply the same technique to the microposts displayed on the user show page.
|
25
|
+
|
26
|
+
Rails Concepts Covered
|
27
|
+
======================
|
28
|
+
|
29
|
+
* Using controller generator
|
30
|
+
* Testing for instance variables in the controller
|
31
|
+
* More association methods, :empty?, :count
|
32
|
+
* Rendering partials by object collection
|
33
|
+
* Time helper
|
34
|
+
|
35
|
+
[chapter_11_2_1]: http://ruby.railstutorial.org/chapters/user-microposts#sec:augmenting_the_user_show_page "Chapter 11.2.1"
|