RailsSpace errata

These are all the known errata as of the first printing:

Chapter 2

  1. p. 19, Fig. 2.4. The Rails version (1.1.2) is out of date. It should read 1.2.3.
  2. p. 24. gemserver should be gem_server
  3. p. 26 At the top of the page, both occurrences of map.connect " should be map.connect '' (one double quote to two single quotes)
  4. p. 31. The two occurrences of @contentforlayout in the first full paragraph should be @content_for_layout
  5. p. 31. In Listing 2.11, "Welcome to RailsSpace!" should be "RailsSpace"
  6. p. 33. linkto should be link_to

Chapter 3

  1. p. 48. The references to Section 4.2.3 should instead be to Section 4.2.2.
  2. p. 54. refl ecting should be reflecting

Chapter 4

  1. p. 79. logs/development.log should be log/development.log.
  2. p. 84. "User foobar created!" should be "User created!"
  3. p. 86. Listing 4.17 is missing the nav div. Listing 4.17 on this site is correct.
  4. p. 89. In the variable interpolation sidebar, the irb session should look like this:
    irb(main):001:0> title = "RailsSpace" 
    => "RailsSpace" 
    irb(main):002:0> "Welcome to #{title}!" 
    => "Welcome to RailsSpace!" 
    irb(main):003:0> 'Welcome to #{title}!' 
    => "Welcome to \#{title}!"
    

    In other words, the first and second instances of #title should have curly braces to give #{title}, while the third #title should also have a backslash at the front, giving \#{title}.

Chapter 5

  1. p. 102. etitle should be @title
  2. p. 105, 108. <legend>Register</legend> in the registration page HTML source views is inconsistent with the registration page from Chapter 4, which has instead <legend>Enter Your Details</legend>.
  3. p. 108. The screen name error in the HTML output is wrong. Instead of
          Screen name is too short (minimum is 4 characters)
        
    it should be
          Screen name must contain only letters, numbers, and underscores  
        
  4. p. 112. At the bottom of the first paragraph, "users(:second)" should be "users(:another)".
  5. p. 119. All occurrences of the word "maximum" within the console output at the top should be "minimum".

Chapter 6

  1. In Rails 2.0.2 use <pre><%= session.to_yaml %></pre>instead of <%= debug(session) %>.
  2. Instant Rails Users - Testing flash[:notice]

    Instant Rails is a bit smarter than regular Rails when it comes to the flash[:notice] assignment and de-assignment. In Instant Rails, as soon as the flash[:notice] is used, it gets nullified. So, the flash message appears, but then this test:

    
      assert_equal "Invalid screen name/password combination", flash[:notice]
          

    fails because the flash is already nil. So, you have to instead check the HTML that was that delivered:

    
      assert_tag :div, :content    => "Invalid screen name/password combination", 
                       :attributes => { :id => "notice" }
          
  3. p. 133. Rails 2.0 users might get errors like
    ActionController::InvalidAuthenticityToken in User#register
    
    Showing user/register.html.erb where line #2 raised:
    
    No :secret given to the #protect_from_forgery call.  Set that or use a
    session store capable of generating its own keys (Cookie Session
    Store).
    This is a known problem in Rails 2. To fix it, comment out the line with the :secret key in app/controllers/application.rb.
  4. pp. 136-139. The screenshots have the Register link right-aligned, but really they should be at the left with the other links.
  5. p. 153. In the box "A rough edge", two instances of unless should be if:
    
          unless session[:user_id] == nil
         
    should be
    
          if session[:user_id] == nil
         
    and
    
          unless session[:user_id].nil?
         
    should be
    
          if session[:user_id].nil?
         
  6. p.175. There is an unnumbered code listing with code that belongs in app/controllers/user_controller.rb. It is numbered as listing 6.47.5 above.
  7. p. 179. Depending on your system, you may have "17 tests, 80 assertions".

Chapter 7

  1. p.201. Listing 7.17 has a stray line return:
          user.authorization_token = Digest::SHA1.hexdigest(
                                       "#{user.screen_name}:
                                        #{user.password}")
    should be
          user.authorization_token = Digest::SHA1.hexdigest(
                                       "#{user.screen_name}:#{user.password}")
  2. p. 221. Listing 7.40. There's an extra space in user.forget! (cookies); i.e., it should just be user.forget!(cookies).

Chapter 8

  1. p. 244. Listing 8.21 def assert_length(boundary, object, attribute, length options = {}) is missing a comma. It should be def assert_length(boundary, object, attribute, length, options = {})
  2. p. 244, footnote. Cross reference should be "7.1.3" instead of "7.13".

Chapter 9

  1. p. 268, last line. <%= text_field_for form, "Last name" %> should be
    <%= text_field_for form, "last_name" %>
  2. p. 276. Listing 9.20 is a snippet of a file, not the entire file, and Spec.new should take an argument setting its user id:
        # Test a saving a blank spec.
        def test_blank
          blank = Spec.new(:user_id => @valid_spec.user.id)
          assert blank.save, blank.errors.full_messages.join("\n")
        end
    To get this to work, you need to add the users fixture to spec_test.rb:
    class SpecTest < Test::Unit::TestCase
      fixtures :specs, :users
      .
      .
      .
    The code listed here on the web site is correct.
  3. p. 283. Listing 9.28 should should really be around the code at the bottom of the page, i.e., first we recall the old code, which should not be called listing 9.28, and then we replace it with new code that is changed and should be listing 9.28. The code listing on the web site is correct.
  4. p. 284. The user controller listing at the bottom of the page should have been numbered, and the code is included here as Listing 9.29.5.
  5. p. 289. Listing 9.34 should be titled db/migrate/006_create_faqs.rb.
  6. p. 296. We refer to Figure 9.9 on the page, but the reader should be aware that Figure 9.9 won't display until the creation of the _sidebar_box.rhtml file in Listing 9.47 on pages 297-298.
  7. p. 301. Listing 9.52 should be titled app/views/profile/show.rhtml

Chapter 10

  1. p. 312. Listing 10.4 is titled app/views/controllers/community_controller.rb but but should be app/controllers/community_controller.rb
  2. p. 317. A reference to app/view/profile/show.rhtml should be app/views/profile/show.rhtml
  3. p. 318. There's a logic error in the calculation of the user's age in the spec model. Listing 10.11, which appears as
      # Return the age using the birthdate.
      def age
        return if birthdate.nil?
        today = Date.today
        if today.month >= birthdate.month and today.day >= birthdate.day
          # Birthday has happened already this year.
          today.year - birthdate.year
        else
          today.year - birthdate.year - 1
        end
      end
    should instead be
      # Return the age using the birthdate.
      def age
        return if birthdate.nil?
        today = Date.today
        if (today.month > birthdate.month) or 
           (today.month == birthdate.month and today.day >= birthdate.day)
          # Birthday has happened already this year.
          today.year - birthdate.year
        else
          today.year - birthdate.year - 1
        end
      end

Chapter 11

  1. p. 331. The command line to install the Ferret plugin spans two lines and it's not clear that it's not supposed to. The full line is:
    
          ruby script/plugin install svn://projects.jkraemer.net/acts_as_ferret/tags/stable/acts_as_ferret
  2. p. 334. Listing 11.8 is missing an end after @users = @users.sort_by { |user| user.spec.last_name }:
    
      def search
        @title = "Search RailsSpace"
        if params[:q]
          query = params[:q]
          # First find the user hits...
          @users = User.find_by_contents(query, :limit => :all)
          # ...then the subhits.
          specs = Spec.find_by_contents(query, :limit => :all)
          faqs  =  Faq.find_by_contents(query, :limit => :all)
    
          # Now combine into one list of distinct users sorted by last name.
          hits = specs + faqs
          @users.concat(hits.collect { |hit| hit.user }).uniq!        
          # Sort by last name (requires a spec for each user).
          @users.each { |user| user.spec ||= Spec.new }      
          @users = @users.sort_by { |user| user.spec.last_name }
        end
      end
        
  3. p. 339. Section 11.1.5 - Depending on which version of Ferret you have installed, you may not get an error at all when searching for "--". They fixed this bug but it is still a good idea to handle exceptions.
  4. p. 342. Listing 11.16 should be titled test/functional/community_controller_test.rb
  5. Some listings are titled app/views/controllers/community_controller.rb but should be app/controllers/community_controller.rb
    1. p. 344. Listing 11.17
    2. p. 345. Listing 11.20
    3. p. 361. Listing 11.30
    4. p. 361. Listing 11.31
  6. p. 343. The test code given in Listing 11.16 requires the creation of the YAML file in test/fixtures/geo_data.yml with some contents like:
          Caltech:
            id: 1
            zip_code: 91125
            latitude: 33.7866
            longitude: -118.299
            city: PASADENA
            state: CA
            county: LOS ANGELES
            type:
        
  7. p. 349. All occurrences of "find_by_sql" should be "find_by_asl".

Chapter 12

  1. p. 370. Listing 12.6 should be titled app/controllers/profile_controller.rb
  2. p. 376. In the footnote,
    ln -s /usr/local/bin/convert/usr/bin
    is missing a space; it should be
    ln -s /usr/local/bin/convert /usr/bin
  3. p. 386. Listing 12.21 should be titled test/test_helper.rb

Chapter 13

  1. p.403. Figure 13.3 The URL is wrong. At some point we changed the user names in the default data set from firstname_lastname to firstinitial_lastname, so Frank Capra's screen name is 'f_capra' and the URL should be http://localhost:3000/email/correspond/f_capra.

Chapter 14

  1. p.419. Listing 14.5 should be test/unit/friendship_test.rb instead of test/units/friendship_test.rb.
  2. p. 430. Add the following validition to the User model to avoid overwriting the default avatar images:
      def validate
        # Protect against overwriting default thumbnail...
        if %w(default_thumbnail default).include?(screen_name)
          errors.add(:screen_name, "cannot be that, nice try though")
        end
      end

Chapter 15

  1. p. 446. Listing 15.3 should be titled db/migrate/009_create_blogs.rb
  2. p. 449. The code output should have "create db/migrate/010_create_posts.rb"
  3. p. 448. For Rails 2.0, replace scaffold_resource with scaffold
  4. p. 449. Listing 15.7 should be titled db/migrate/010_create_posts.rb
  5. p. 454. Listing 15.9 should be titled app/models/post.rb
  6. p. 457. There is a missing listing number for the posts controller code on this page, it is included on the web site as Listing 15.11.5 above. Also, the second line should read helper :profile, :avatar.
  7. p. 458. There's a security flaw that allows users to edit others' posts as long as the URL contains their blog id; i.e., if yours is blog 2, you can edit post 17 even if it isn't yours by going to /blogs/2/posts/17;edit. The following code fixes this:
    class PostsController < ApplicationController
      helper :profile, :avatar
      before_filter :protect, :protect_blog
      before_filter :protect_post, :only => [:show, :edit, :update, :destroy]
      .
      .
      .
      
      private
    
      # Ensure that user is blog owner, and create @blog.
      def protect_blog
        @blog = Blog.find(params[:blog_id])
        user = User.find(session[:user_id])
        unless @blog.user == user
          flash[:notice] = "That isn't your blog!"
          redirect_to hub_url
          return false
        end
      end
      
      def protect_post
        post = Post.find(params[:id])    
        unless post.blog == @blog
          flash[:notice] = "That isn't your blog post!"
          redirect_to hub_url
          return false
        end
      end
    end
  8. p. 477. To test the code in the erratum on p. 458, change the Posts fixture in test/fixtures/posts.yml to
    # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
    one:
      id: 1
      blog_id: 1
      title: MyString
      body: MyText
      created_at: 2007-01-18 08:43:03
      updated_at: 2007-01-18 08:43:03
    two:
      id: 2
      blog_id: 2
      title: MyString2
      body: MyText
      created_at: 2007-01-18 08:43:03
      updated_at: 2007-01-18 08:43:03
    
    and then add this to the Posts controller test:
    def test_post_blog_mismatch
      wrong_post = posts(:two)  # Post exists, but belongs to wrong blog.
      get :edit, :id => wrong_post, :blog_id => @post.blog
      assert_response :redirect
      assert_redirected_to hub_url
      assert_equal "That isn't your blog post!", flash[:notice]
    end
       

Chapter 16

  1. p. 480. The code output should have "db/migrate/011_create_comments.rb"
  2. p. 480. Listing 16.1 should be titled db/migrate/011_create_comments.rb
  3. p. 483. Listing 16.5 There should be a vertical ellipsis ... before private
  4. p. 486. The reference in the second paragraph to Section 6.2.2 should be 6.2.3.
  5. p. 503. In Listing 16.28, change
    fixtures :comments, :posts, :blogs, :users, :specs
    to
    fixtures :comments, :posts, :blogs, :users, :specs, :geo_data

Back cover

  1. "RailSpace social network" should be "RailsSpace social network"