tft_rails 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/README.md +14 -0
  2. data/lib/generators/chapter07/begin/begin_generator.rb +7 -0
  3. data/lib/generators/chapter07/begin/templates/spec/spec_helper.rb +10 -0
  4. data/lib/generators/chapter08_09/begin/instructions.md +8 -1
  5. data/lib/generators/chapter10/begin/templates/lib/tasks/{same_data.rake → sample_data.rake} +0 -0
  6. data/lib/generators/chapter10/solutions/snippets/migration_add_admin_to_users.rb +1 -1
  7. data/lib/generators/chapter11_1/begin/templates/lib/tasks/{same_data.rake → sample_data.rake} +0 -0
  8. data/lib/generators/chapter11_1/solutions/templates/app/{model → models}/micropost.rb +1 -1
  9. data/lib/generators/chapter11_1/solutions/templates/app/{model → models}/user.rb +0 -0
  10. data/lib/generators/chapter11_2/solutions/solutions_generator.rb +6 -0
  11. data/lib/generators/chapter11_3/begin/templates/app/views/pages/home.html.erb +24 -0
  12. data/lib/generators/chapter11_3/begin/templates/app/views/shared/_feed.html.erb +6 -0
  13. data/lib/generators/chapter11_3/begin/templates/app/views/shared/_feed_item.html.erb +14 -0
  14. data/lib/generators/chapter11_3/begin/templates/app/views/shared/_micropost_form.html.erb +9 -0
  15. data/lib/generators/chapter11_3/begin/templates/app/views/shared/_user_info.html.erb +11 -0
  16. data/lib/generators/chapter11_3/begin/templates/spec/controllers/microposts_controllers_11_3_spec.rb +1 -0
  17. data/lib/generators/chapter11_3/begin/templates/spec/models/user_11_3_spec.rb +31 -0
  18. data/lib/generators/chapter11_3/begin/templates/spec/requests/micropost_11_3_spec.rb +41 -0
  19. data/lib/generators/chapter11_3/solutions/solutions_generator.rb +22 -0
  20. data/lib/generators/chapter11_3/solutions/templates/app/controllers/microposts_controller.rb +20 -0
  21. data/lib/generators/chapter11_3/solutions/templates/app/controllers/pages_controller.rb +22 -0
  22. data/lib/generators/chapter11_3/solutions/templates/app/views/microposts/_micropost.html.erb +15 -0
  23. data/lib/generators/chapter11_3/solutions/templates/app/views/pages/home.html.erb +24 -0
  24. data/lib/generators/chapter11_3/solutions/templates/app/views/shared/_error_messages.html.erb +13 -0
  25. data/lib/generators/chapter11_3/solutions/templates/app/views/shared/_feed.html.erb +6 -0
  26. data/lib/generators/chapter11_3/solutions/templates/app/views/shared/_feed_item.html.erb +21 -0
  27. data/lib/generators/chapter11_3/solutions/templates/app/views/shared/_micropost_form.html.erb +9 -0
  28. data/lib/generators/chapter11_3/solutions/templates/app/views/shared/_user_info.html.erb +11 -0
  29. metadata +22 -6
data/README.md CHANGED
@@ -60,6 +60,20 @@ a wonderful job to illustrate many concepts for teaching, but it is no replaceme
60
60
  that has been peer-reviewed by many experienced developers and is in use in many commercial applications. Devise is the
61
61
  current industry standard solution and was used here.
62
62
 
63
+ Adding to TFT Rails
64
+ -------------------
65
+
66
+ To modify the exercises, make your code changes, then run all chapters in
67
+ successive order in a few rails app. After every solutions generator, the
68
+ specs should run clean.
69
+
70
+ TODO: Rig up a test suite which will create a new rails app, then install
71
+ all chapters and solutions in successive order and run the spec suite every time.
72
+ This may necessitate construction our own Test Runner or similar. I'm not
73
+ sure how to do this.
74
+
75
+ TODO: Add Chapter 12. The project currently contains Chapters 7 through 11, adapted for Devise.
76
+
63
77
  Sponsors
64
78
  --------
65
79
 
@@ -7,6 +7,13 @@ module Chapter07
7
7
  directory(self.class.source_root, Rails.root, :force => true)
8
8
  end
9
9
 
10
+ def insert_gitignore
11
+ dest = File.join(Rails.root,'.gitignore')
12
+ insert_into_file(dest, :before => /\Z/) do # insert before end
13
+ "\n.idea\n"
14
+ end
15
+ end
16
+
10
17
  def augment_gemfile
11
18
  gem 'devise', '~> 1.3.4'
12
19
  gem 'gravatar_image_tag', '~> 1.0.0'
@@ -7,6 +7,16 @@ require 'rspec/rails'
7
7
  # in spec/support/ and its subdirectories.
8
8
  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
9
9
 
10
+ Webrat.configure do |config|
11
+ config.mode = :rack
12
+ end
13
+
14
+ module Webrat::Logging
15
+ def logger
16
+ Rails.logger # log to test.log, rather than webrat.log
17
+ end
18
+ end
19
+
10
20
  RSpec.configure do |config|
11
21
  # == Mock Framework
12
22
  #
@@ -50,9 +50,16 @@ The Devise sign-in page meets our needs and doesn't need customizing.
50
50
  However, we need to work on the layout to make sure that it shows a "Sign out" link
51
51
  if a user is logged in, and a "Sign in" link only if a user is not logged in.
52
52
 
53
- [Devise][devise] offers the controller methods `user_signed_in?` and `current_user`
53
+ [Devise][devise] offers the controller methods `signed_in?` and `current_user`
54
54
  to report on the current login status. The first method returns `true` or `false`
55
55
  depending on whether a user logged in, the second returns the actual user object,
56
56
  or `nil` if no user is logged in.
57
57
 
58
+ (Note that Devise supports multiple sign-in scopes, e.g. for regular users and
59
+ for admins. The method `signed_in?` checks that any scope is signed in. To
60
+ check for a specific scope, the method `user_signed_in?` is available. For the
61
+ purpose of RailsTutorial with Devise, this distinction is not important since
62
+ we only have one type of user. Admin privileges are implemented differently,
63
+ with the admin flag)
64
+
58
65
  [devise]: https://github.com/plataformatec/devise "Devise on github"
@@ -1,6 +1,6 @@
1
1
  class AddAdminToUsers < ActiveRecord::Migration
2
2
  def self.up
3
- add_column :users, :admin, :boolean
3
+ add_column :users, :admin, :boolean, :default => false, :null => false
4
4
  end
5
5
 
6
6
  def self.down
@@ -2,7 +2,7 @@ class Micropost < ActiveRecord::Base
2
2
 
3
3
  belongs_to :user
4
4
 
5
- default_scope order('created_at DESC')
5
+ default_scope order('microposts.created_at DESC')
6
6
 
7
7
  validates :user_id, :presence => true
8
8
  validates :content, :presence => true, :length => {:maximum => 140}
@@ -1,6 +1,12 @@
1
1
  module Chapter11_2
2
2
  module Generators
3
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
+
4
10
  end
5
11
  end
6
12
  end
@@ -0,0 +1,24 @@
1
+ <% if signed_in? %>
2
+ <table class="front" summary="For signed-in users">
3
+ <tr>
4
+ <td class="main">
5
+ <h1 class="micropost">What's up?</h1>
6
+ <%#= micropost form %>
7
+ <%#= feed of microposts %>
8
+ </td>
9
+ <td class="sidebar round">
10
+ <%#= sidebar with user info (name, image link) %>
11
+ </td>
12
+ </tr>
13
+ </table>
14
+ <% else %>
15
+ <h1>Sample App</h1>
16
+
17
+ <p>
18
+ This is the home page for the
19
+ <a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
20
+ sample application.
21
+ </p>
22
+
23
+ <%= link_to "Sign up now!", signup_path, :class => "signup_button round" %>
24
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <%# if there are feed items %>
2
+ <table class="microposts" summary="User microposts">
3
+ <%#= display feed items here %>
4
+ </table>
5
+ <%#= pagination ? %>
6
+ <%# end %>
@@ -0,0 +1,14 @@
1
+ <tr>
2
+ <td class="gravatar">
3
+ <%# image %>
4
+ </td>
5
+ <td class="micropost">
6
+ <span class="user">
7
+ <%#= link to user %>
8
+ </span>
9
+ <span class="content"><%#= content of feed entry (i.e. a micropost) %></span>
10
+ <span class="timestamp">
11
+ Posted <%#= posting time of micropost %> ago.
12
+ </span>
13
+ </td>
14
+ </tr>
@@ -0,0 +1,9 @@
1
+ <%#= form helper %>
2
+ <%#= error display %>
3
+ <div class="field">
4
+ <%#= content form field %>
5
+ </div>
6
+ <div class="actions">
7
+ <%#= submit button %>
8
+ </div>
9
+ <%# end %>
@@ -0,0 +1,11 @@
1
+ <div class="user_info">
2
+ <a href="<%#= link to user %>">
3
+ <%#= user's image %>
4
+ <span class="user_name">
5
+ <%#= user's name %>
6
+ </span>
7
+ <span class="microposts">
8
+ <%# number of user's microposts %>
9
+ </span>
10
+ </a>
11
+ </div>
@@ -74,6 +74,7 @@ describe MicropostsController do
74
74
  wrong_user = Factory(:user, :email => Factory.next(:email))
75
75
  sign_in(wrong_user)
76
76
  @micropost = Factory(:micropost, :user => @user)
77
+ request.env["HTTP_REFERER"] = root_path
77
78
  end
78
79
 
79
80
  it "should deny access" do
@@ -0,0 +1,31 @@
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
+ describe "status feed" do
14
+
15
+ it "should have a feed" do
16
+ @user.should respond_to(:feed)
17
+ end
18
+
19
+ it "should include the user's microposts" do
20
+ @user.feed.include?(@mp1).should be_true
21
+ @user.feed.include?(@mp2).should be_true
22
+ end
23
+
24
+ it "should not include a different user's microposts" do
25
+ mp3 = Factory(:micropost,
26
+ :user => Factory(:user, :email => Factory.next(:email)))
27
+ @user.feed.include?(mp3).should be_false
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Microposts" do
4
+
5
+ before(:each) do
6
+ user = Factory(:user)
7
+ visit signin_path
8
+ fill_in :email, :with => user.email
9
+ fill_in :password, :with => user.password
10
+ click_button
11
+ end
12
+
13
+ describe "creation" do
14
+
15
+ describe "failure" do
16
+
17
+ it "should not make a new micropost" do
18
+ lambda do
19
+ visit root_path
20
+ fill_in :micropost_content, :with => ""
21
+ click_button
22
+ response.should render_template('pages/home')
23
+ response.should have_selector("div#error_explanation")
24
+ end.should_not change(Micropost, :count)
25
+ end
26
+ end
27
+
28
+ describe "success" do
29
+
30
+ it "should make a new micropost" do
31
+ content = "Lorem ipsum dolor sit amet"
32
+ lambda do
33
+ visit root_path
34
+ fill_in :micropost_content, :with => content
35
+ click_button
36
+ response.should have_selector("span.content", :content => content)
37
+ end.should change(Micropost, :count).by(1)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,7 +1,29 @@
1
1
  module Chapter11_3
2
2
  module Generators
3
3
  class SolutionsGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../templates", __FILE__)
4
5
 
6
+ def copy_app_tree
7
+ directory(self.class.source_root, Rails.root)
8
+ end
9
+
10
+ def add_microposts_resource
11
+ dest = File.join(Rails.root,'config','routes.rb')
12
+ insert_into_file(dest, :after => %r{resources\s+:users.*$}) do
13
+ "\n resources :microposts, :only => [:create, :destroy]"
14
+ end
15
+ end
16
+
17
+ def add_feed_method_to_user
18
+ dest = File.join(Rails.root, 'app', 'models', 'user.rb')
19
+ insert_into_file(dest, :before => /end\s*\Z/) do # insert before end
20
+ <<-CODE.gsub(/^\s+\|/,' ')
21
+ |def feed
22
+ | microposts
23
+ |end
24
+ CODE
25
+ end
26
+ end
5
27
 
6
28
  end
7
29
  end
@@ -0,0 +1,20 @@
1
+ class MicropostsController < ApplicationController
2
+ before_filter :authenticate_user!
3
+
4
+ def create
5
+ @micropost = current_user.microposts.build(params[:micropost])
6
+ if @micropost.save
7
+ flash[:success] = "Micropost created!"
8
+ redirect_to root_path
9
+ else
10
+ render 'pages/home'
11
+ end
12
+ end
13
+
14
+ def destroy
15
+ # .try will call the method given, unless the caller is nil
16
+ current_user.microposts.find_by_id(params[:id]).try(:destroy)
17
+ redirect_to :back
18
+ end
19
+
20
+ end
@@ -0,0 +1,22 @@
1
+ class PagesController < ApplicationController
2
+ def home
3
+ @title = "Home"
4
+ if signed_in?
5
+ @micropost = current_user.microposts.build
6
+ @feed_items = current_user.feed.paginate(:page => params[:page])
7
+ end
8
+ end
9
+
10
+ def contact
11
+ @title = 'Contact'
12
+ end
13
+
14
+ def about
15
+ @title = 'About'
16
+ end
17
+
18
+ def help
19
+ @title = 'Help'
20
+ end
21
+
22
+ end
@@ -0,0 +1,15 @@
1
+ <tr>
2
+ <td class="micropost">
3
+ <span class="content"><%= micropost.content %></span>
4
+ <span class="timestamp">
5
+ Posted <%= time_ago_in_words(micropost.created_at) %> ago.
6
+ </span>
7
+ </td>
8
+ <% if signed_in? && current_user.id == micropost.user_id %>
9
+ <td>
10
+ <%= link_to "delete", micropost, :method => :delete,
11
+ :confirm => "You sure?",
12
+ :title => micropost.content %>
13
+ </td>
14
+ <% end %>
15
+ </tr>
@@ -0,0 +1,24 @@
1
+ <% if signed_in? %>
2
+ <table class="front" summary="For signed-in users">
3
+ <tr>
4
+ <td class="main">
5
+ <h1 class="micropost">What's up?</h1>
6
+ <%= render 'shared/micropost_form' %>
7
+ <%= render 'shared/feed' %>
8
+ </td>
9
+ <td class="sidebar round">
10
+ <%= render 'shared/user_info' %>
11
+ </td>
12
+ </tr>
13
+ </table>
14
+ <% else %>
15
+ <h1>Sample App</h1>
16
+
17
+ <p>
18
+ This is the home page for the
19
+ <a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
20
+ sample application.
21
+ </p>
22
+
23
+ <%= link_to "Sign up now!", signup_path, :class => "signup_button round" %>
24
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <% if object.errors.any? %>
2
+ <div id="error_explanation">
3
+ <h2><%= pluralize(object.errors.count, "error") %>
4
+ prohibited this <%= object.class.to_s.underscore.humanize.downcase %>
5
+ from being saved:</h2>
6
+ <p>There were problems with the following fields:</p>
7
+ <ul>
8
+ <% object.errors.full_messages.each do |msg| %>
9
+ <li><%= msg %></li>
10
+ <% end %>
11
+ </ul>
12
+ </div>
13
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <% if @feed_items.present? %>
2
+ <table class="microposts" summary="User microposts">
3
+ <%= render :partial => 'shared/feed_item', :collection => @feed_items %>
4
+ </table>
5
+ <%= will_paginate @feed_items %>
6
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <tr>
2
+ <td class="gravatar">
3
+ <%= link_to gravatar_for(feed_item.user), feed_item.user %>
4
+ </td>
5
+ <td class="micropost">
6
+ <span class="user">
7
+ <%= link_to feed_item.user.name, feed_item.user %>
8
+ </span>
9
+ <span class="content"><%= feed_item.content %></span>
10
+ <span class="timestamp">
11
+ Posted <%= time_ago_in_words(feed_item.created_at) %> ago.
12
+ </span>
13
+ </td>
14
+ <% if signed_in? && current_user.id == feed_item.user_id %>
15
+ <td>
16
+ <%= link_to "delete", feed_item, :method => :delete,
17
+ :confirm => "You sure?",
18
+ :title => feed_item.content %>
19
+ </td>
20
+ <% end %>
21
+ </tr>
@@ -0,0 +1,9 @@
1
+ <%= form_for @micropost do |f| %>
2
+ <%= render 'shared/error_messages', :object => f.object %>
3
+ <div class="field">
4
+ <%= f.text_area :content %>
5
+ </div>
6
+ <div class="actions">
7
+ <%= f.submit "Submit" %>
8
+ </div>
9
+ <% end %>
@@ -0,0 +1,11 @@
1
+ <div class="user_info">
2
+ <a href="<%= user_path(current_user) %>">
3
+ <%= gravatar_for current_user, :size => 30 %>
4
+ <span class="user_name">
5
+ <%= current_user.name %>
6
+ </span>
7
+ <span class="microposts">
8
+ <%= pluralize(current_user.microposts.count, "micropost") %>
9
+ </span>
10
+ </a>
11
+ </div>
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: tft_rails
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.6.1
5
+ version: 0.6.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Wolfram Arnold
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-07-22 00:00:00 Z
13
+ date: 2011-07-25 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rdiscount
@@ -38,8 +38,24 @@ files:
38
38
  - lib/generators/chapter11_3/begin/instructions.md
39
39
  - lib/generators/chapter11_3/begin/templates/spec/controllers/pages_controller_11_3_spec.rb
40
40
  - lib/generators/chapter11_3/begin/templates/spec/controllers/microposts_controllers_11_3_spec.rb
41
+ - lib/generators/chapter11_3/begin/templates/spec/models/user_11_3_spec.rb
42
+ - lib/generators/chapter11_3/begin/templates/spec/requests/micropost_11_3_spec.rb
43
+ - lib/generators/chapter11_3/begin/templates/app/views/pages/home.html.erb
44
+ - lib/generators/chapter11_3/begin/templates/app/views/shared/_user_info.html.erb
45
+ - lib/generators/chapter11_3/begin/templates/app/views/shared/_micropost_form.html.erb
46
+ - lib/generators/chapter11_3/begin/templates/app/views/shared/_feed.html.erb
47
+ - lib/generators/chapter11_3/begin/templates/app/views/shared/_feed_item.html.erb
41
48
  - lib/generators/chapter11_3/solutions/USAGE
42
49
  - lib/generators/chapter11_3/solutions/solutions_generator.rb
50
+ - lib/generators/chapter11_3/solutions/templates/app/controllers/microposts_controller.rb
51
+ - lib/generators/chapter11_3/solutions/templates/app/controllers/pages_controller.rb
52
+ - lib/generators/chapter11_3/solutions/templates/app/views/pages/home.html.erb
53
+ - lib/generators/chapter11_3/solutions/templates/app/views/microposts/_micropost.html.erb
54
+ - lib/generators/chapter11_3/solutions/templates/app/views/shared/_user_info.html.erb
55
+ - lib/generators/chapter11_3/solutions/templates/app/views/shared/_error_messages.html.erb
56
+ - lib/generators/chapter11_3/solutions/templates/app/views/shared/_micropost_form.html.erb
57
+ - lib/generators/chapter11_3/solutions/templates/app/views/shared/_feed.html.erb
58
+ - lib/generators/chapter11_3/solutions/templates/app/views/shared/_feed_item.html.erb
43
59
  - lib/generators/chapter07/begin/USAGE
44
60
  - lib/generators/chapter07/begin/begin_generator.rb
45
61
  - lib/generators/chapter07/begin/instructions.md
@@ -127,7 +143,7 @@ files:
127
143
  - lib/generators/chapter10/begin/instructions.md
128
144
  - lib/generators/chapter10/begin/snippets/custom.css
129
145
  - lib/generators/chapter10/begin/snippets/factories.rb
130
- - lib/generators/chapter10/begin/templates/lib/tasks/same_data.rake
146
+ - lib/generators/chapter10/begin/templates/lib/tasks/sample_data.rake
131
147
  - lib/generators/chapter10/begin/templates/spec/controllers/users_controller_10_spec.rb
132
148
  - lib/generators/chapter10/begin/templates/spec/models/user_10_spec.rb
133
149
  - lib/generators/chapter10/begin/templates/app/views/layouts/application.html.erb
@@ -159,15 +175,15 @@ files:
159
175
  - lib/generators/chapter11_1/begin/USAGE
160
176
  - lib/generators/chapter11_1/begin/begin_generator.rb
161
177
  - lib/generators/chapter11_1/begin/instructions.md
162
- - lib/generators/chapter11_1/begin/templates/lib/tasks/same_data.rake
178
+ - lib/generators/chapter11_1/begin/templates/lib/tasks/sample_data.rake
163
179
  - lib/generators/chapter11_1/begin/templates/spec/models/user_11_1_spec.rb
164
180
  - lib/generators/chapter11_1/begin/templates/spec/models/microposts_11_1_spec.rb
165
181
  - lib/generators/chapter11_1/solutions/USAGE
166
182
  - lib/generators/chapter11_1/solutions/solutions_generator.rb
167
183
  - lib/generators/chapter11_1/solutions/snippets/migration_create_microposts.rb
168
184
  - lib/generators/chapter11_1/solutions/templates/spec/factories.rb
169
- - lib/generators/chapter11_1/solutions/templates/app/model/user.rb
170
- - lib/generators/chapter11_1/solutions/templates/app/model/micropost.rb
185
+ - lib/generators/chapter11_1/solutions/templates/app/models/user.rb
186
+ - lib/generators/chapter11_1/solutions/templates/app/models/micropost.rb
171
187
  - LICENSE
172
188
  - Rakefile
173
189
  - Gemfile