(borrowed from http://manning.com/black/excerpt_errata.html)
The errata on this page is organized into three categories, in descending order of importance to the reader:
The server start example fails because Rails expects a database and we fail to create one. See this entry on beginningrails.com for a full explanation and workaround
The url options given to form_tag in Listing 6-7 don't include an id parameter, which is necessary to identify the record in the update action. It should read:
<%= form_tag :action => 'update', :id => :user %>
Listing 6-8 contains a current_user method that doesn't yet exist. In fact, we don't create that method until Listing 6-21 on Page 179.
The correct object on which to call update_attributes is the user object in @user.
def update
@user = User.find(params[:id])
if @user.update_attributes(params[:user])
flash[:notice] = 'Information updated'
redirect_to event_url(event)
else
render :action => 'edit'
end
end
The template for the login action appears to be missing! The login.rhtml template should be as follows:
<h1>Please Login</h1>
<% form_tag :action => 'login' do %>
<p><label>Login:<br />
<%= text_field_tag :login %></label></p>
<p><label>Password:<br />
<%= password_field_tag :password %></label></p>
<p>
<%= submit_tag 'Login' %>
</p>
<% end %>
Listing 7-9 creates an orphaned event in the save_event action.
Each event belongs to a user, and after a new event record is created (Event#after_create) we register the owner for that event (ensure_owner_attends). This all takes place in the Event model.
When save_event creates an orphaned event, and the ensure_owner_attends callback fires, it attempts to create a new Registration, only it fails because Event#user is nil. This results in an AssociationTypeMismatch error: when creating the Registration, Active Record expected a User object and an Event object, but instead of a User, it got a nil object instead.
To fix this, we need to make sure the event in question has a user before we attempt to save it.
Listing 7-9 on page 211 needs to be changed from this:
def save_event
Event.create(params[:event])
count_events
render :partial => "events_count"
end
to this:
def save_event
current_user.events.create(params[:event])
count_events
render :partial => "events_count"
end
Notice how we're going through the current_user to create the event:
current_user.events.create
Of course, this will fail if there is no current_user (i.e., if current_user is nil). We can solve this a couple of ways. The most obvious solution is to place a login requirement as a before_filter in the controller (just like we did in the events controller). This will ensure that you can't get to the save_event action without a current_user.
class AjaxController < ApplicationController
before_filter :authenticate
# ...
end
But since an event can't be saved without a user, we really need to enforce this as a business logic requirement. We should therefore place a validation on the Event model to validate the presence of the User. We'll still need the login requirement on the controller, but at least our model clearly expresses our logic requirements.
class Event < ActiveRecord::Base
#...
validates_presence_of :user
#...
end
Now when we attempt to create an orphaned event, we'll trigger a validation error and the event won't be saved. This is preferable to raising an exception.
e = Event.new
e.valid? # => false
e.errors.on(:user) # => "can't be blank"
The test_should_create_event test in Listing 9-4 doesn't associate the new event with a User, and as such, will fail. The code listing should be as follows:
def test_should_create_event
event = Event.new
event.user = users(:eugene)
event.title = "Test Event"
event.url = "http://example.com"
event.description = "Test description"
event.location = "Test location"
event.occurs_on = 1.week.from_now.to_date
assert event.save
end
The 5th paragraph refers to a dev directory, which is a vestige of the manuscript's past.
"In this case, it will create a subdirectory in dev called events," should read: "In this case, it will create a subdirectory in the current working directory called events."
Closing parentheses in the event instantiation example are in the wrong place [Adam McClure]. Should be as follows:
event = Event.new(:title => "Jeff's Birthday Party",
:location => "Flaming Moe's",
:url => "http://quotedprintable.com",
:description => "Bring gifts to *me*",
:occurs_on => "2007-10-13")
The Event.create example has the closing parentheses in the wrong place [Adam McClure]. Should be as follows:
event = Event.create(:title => "RuPy Conference",
:location => "Poznan, Poland",
:url => "http://ruby.wmid.amu.edu.pl",
:description => "See, we can all get along!",
:occurs_on => "2007-04-14")
The event attributes example has the ending curly bracket in the wrong place [Adam McClure]. Should be as follows:
attributes = { :title => "Jeff's Birthday Party",
:location => "Flaming Moe's",
:url => "http://quotedprintable.com",
:description => "Bring gifts to *me*",
:occurs_on => "2007-10-13" }
The Caution box under "Deleting with Conditions" incorrectly reads "If you use delete without any arguments, it will delete all rows in the table."
It means to refer to delete_all, not delete. delete_all without any arguments will delete all records in the database, but delete requires an ID as an argument. The caution should read:
Caution: If you use delete_all without any arguments, it will delete all rows in the table, so be careful! Most of the time, you'll pass it a string of conditions.
The 2nd paragraph under 'Creating One-to-One Associations' cites incorrect table names.
"Assume we have Employee and Address models, and the corresponding users and profiles tables have the appropriate columns"
should read:
"Assume we have Employee and Address models, and the corresponding employees and addresses tables have the appropriate columns."
In Table 5-4, "Methods Added by the has_many association" there are two references to association.clear; the first description is incorrect. The correct behavior is described in the second definition on page 104:
@user.events.clear # => Clears all associated objects from the association by setting their foreign keys to NULL.
The first description should be deleted.
The first line of code on the page shows a registrations (plural) model generation command, despite the fact that the model we subsequently work with is named in the singular. Model names should be singular. [Adam McClure]
The line should read:
$ ./script/generate model Registration
The migration in Listing 5-13 incorrectly creates the column note with type string. This should be a text field:
t.column :note, :text
The first paragraph after Listing 5-26 (beginning with "We're doing a bit more error checking this time..." should be deleted. It refers to a section of code that was removed in later revisions.
The root route in Listing 6-1 contains an erroneous comma immediately after the method invocation (map.root,). The correct route definition should be as follows:
map.root '', :controller => 'events'
3rd paragraph under the heading "Automatic Local Variable Assignment in Partials":
"Here's a list template (app/views/articles/list.rhtml)..." should read "Here's an index template (app/views/articles/index.rhtml)..."
In the 'Results' section under the heading "Storing Sessions in the Database," 007_add_sessions.rb should be 008_add_sessions.rb
Listing 7-5 is missing quotes around the JavaScript callbacks (:loading and :complete). The example should read as follows:
<%= link_to_remote "Ajax call with indicator",
:update => "date",
:loading => "$('indicator').show()",
:complete => "$('indicator').hide()",
:url => { :controller => "ajax",
:action => "current_date" } %>
Listing 7-7 (repeated on Page 224) is missing quotes around the JavaScript callbacks (:loading and :complete). The example should read as follows:
<% form_remote_tag :update => "count",
:loading => "$('indicator_form').show()",
:complete => "$('indicator_form').hide()",
:url => { :controller => 'ajax',
:action => "save_event" } do %>
Listing 7-11 is missing quotes around the JavaScript callbacks (:loading and :complete). The example should read as follows:
<% form_remote_tag :update => "count",
:loading => "$('indicator_form').show()",
:complete => "eventAdded()",
:url => { :controller => 'ajax',
:action => "save_event" } do %>
The paragraph beginning with "The first option is the URL of the action," should read:
The first option is the name of the element on which the observer is to act. The second indicates the frequency, in seconds, at which changes to the form will be detected. The last option is the URL of the action to which we'll send the Ajax request.
Listing 7-15 includes a reference to tagging (@event.tag_with(params[:tags]), however we don't add tagging until Page 282 in Chapter 10.
The line in question should be removed from the code listing.
Listing 7-21 is missing quotes around the JavaScript :loading callback. The example should read as follows:
<% form_remote_tag(:loading => "$('indicator_form').show()",
:url => {:controller => 'ajax',
:action => 'save_event'}) do %>
Listing 8-8 incorrectly defines the method as invite_friend. The method should be named email_friend as in other examples.
def email_friend
#...
end
Listing 9-14, in the test_create case, the redirection assertion refers to the (since replaced) 'list' action. It should read assert_redirected_to :action => 'index'.
Listing 9-15, in the test_destroy case, the redirection assertion refers to the (since replaced) 'list' action. It should read assert_redirected_to :action => 'index'.
Listing 9-20, in the test_should_login_create_event_and_logout case, the redirection assertion refers to the (since replaced) 'list' action. It should read assert_redirected_to :action => 'index'.
The example given to run the user_stories test omits the call to the ruby interpreter and the path to the file. It should read (just after "Here's what we get when we run the test"):
$ ruby test/integration/user_stories_test.rb
"Ruby is considerably more powerful that either PHP or ASP" should read "Ruby is considerably more powerful than either PHP or ASP." [Firas Al-Ragom]
In the fourth paragraph, "You can see Rails's opinion," should read "You can see Rails' opinion."
"Congratulations! You've put Rails" should read "Congratulations! You've put Ruby on Rails."
In the rails command example (under the heading "Creating the Events Application"), the prompt should have a space between the $ and the rails command
The Note at top of page is truncated:
"Depending on how your environment is set up, you might not need to specify the username"
should read
"Depending on how your environment is set up, you might not need to specify the username under which to create the database."
Mid page, 2nd bullet point reads: "we'll cover testing applications in Chapter 8." It should read "we'll cover testing applications in Chapter 9."
The 4th sentence in the Summary begins with "Then the scaffolding... ." It should read "The scaffolding... ."
The last paragraph incorrectly reports the number of records created: "We've already created three new records," should read "We've already create four new records."
The last paragraph on the page reads "models are regular Ruby objects" should read "models are regular Ruby classes."
Listing 5-2 has incorrect indentation. The create_table statement should look as follows:
create_table :users do |t|
t.column :login, :string
t.column :email, :string
t.column :password, :string
end
The 1st paragraph incorrectly refers to the password field as hashed_password:
"Along with the standard login and email fields, we're specifying a hashed_password field" should read "Along with the standard login and email fields, we're specifying a password field."
3rd paragraph, last sentence, "...runs whenever the user saves the object," should read "..runs whenever the object is saved."
The link_to helper example shows incorrect output for the url generation. The example uses albums_url (not albums_path) and will therefore produce a full URL, including the host and port. The example should read:
link_to "Albums", albums_path #=> <a href="/albums/list">Albums</a>
Under 'Creating a Template', the URL to test the newly created template is incorrect. It should read: "Make sure your local web server is running (./script/server), and open http://localhost:3000/users/new."
2nd paragraph, 3rd sentence: "Rails will redirect to the index action in the users controller" should read "Rails will redirect to the events controller."
At the bottom of the page, "see Listing 5-28 in Chapter 5" should read, "see Listing 5-29 in Chapter 5."
2nd paragraph under "Ajax and Rails": "One of Rails's main features..." should read "One of Rails' main features."
2nd paragraph under "Ajax and Rails," last sentence on the page: "...that will enable you to implement event the most advanced techniques" should read "...that will enable you to implement even the most advanced techniques."
2nd paragraph under "Using Ajax Helpers": There is an extra space in the path given to the main layout file. It should read: app/views/layouts/application.rhtml.
In the 3rd paragraph, in the sentence, "Here's an example that will apply the highlight effect to a specific element in response to clicking a link," the word 'highlight' should not be marked up as code.
In Table 7-4, the example given for the select function incorrectly reads page.selector '#items li'. It should read page.select '#items li'.
Table 8-3: the @recipients variable is incorrectly shown in the singular form. It should read @recipients.
The first paragraph contains an incorrect statement ("we've also modified the subject line") that should be deleted: "In addition to the new arguments, we've also modified the subject line, used the @content_type variable to set the content type to text/html (instead of text/plain), and added some options to the @body hash..." should read: "In addition to the new arguments, we've also used the @content_type variable to set the content type to text/html (instead of text/plain), and added some options to the @body hash..."
The first set of bullet points under the heading "How Rails Handles Testing" should not be terminated with periods.
The first sentence under the "Adding a Create Test" heading and the caption in Listing 9-4 contains an incorrect path to the file in question. The correct path is "test/unit/event_test.rb." Note that "event" is singular, not plural.
The path given to the template in the first paragraph is incorrect. Instead of "app/views/events/list.rhtml," it should read "app/views/events/index.rhtml."
2nd paragraph, "The @first_id variable is the one we set in the index method," should read "The @first_id variable is the one we set in the setup method."
The first paragraph refers to the (since replaced) 'list' action when describing the assert_redirected_to assertion.
"We assert that the response is a redirect to the list action" should read "We assert that the response is a redirect to the index action."
Listing 9-20 refers to the (since replaced) 'list' action on the events controller when asserting the redirection after creating an event.
The corrected code is given below, with a few lines for context.
def test_should_login_create_event_and_logout
#...
post '/events/create', :event => {#...}
assert assigns(:event).valid?
assert_response :redirect
assert_redirected_to :action => 'index'
#...
end
First paragraph, in the sentence "The return value of the registered_user, then, is a fresh integration session object", the word 'session' should not be marked up as code.
Table 10-2, description of 'Rakefile,' "...run the tests for this plugin and generated Ruby documentation," should read "...run the tests for this plugin and generate documentation."
First paragraph, "...a plugin usually adds one or more methods in the class or object in which it is acting," should read "...a plugin usually adds one or more methods to the class or object on which it is acting."
First paragraph under the "Summary" heading: "By creating plugins, you make your application focus more on it business logic," should read "By creating plugins, you enable your application to focus more on its business logic."
First paragraph, last sentence, "If its on your local file system..." should read "If it's on your local file system."
First paragraph, second sentence, "Suppose you would like to clear out a temporary folder every time you deployed?" should not be terminated with a question mark.
In Table A-1, the description of Constants (e.g. SERVER_IP) states that you can create them by naming a variable in "all uppercase characters." This is technically incorrect. Only the first character need be uppercase. The first sentence of the description should therefore read:
You can create a constant in Ruby by capitalizing the first letter of your variable, however, it's a convention that constants are written in all uppercase characters.
First paragraph, first sentence, "If a method yields arguments to a block, the methods are named between two pipe characters..." should read "If a method yields arguments to a block, the arguments are named between two pipe characters..."
The say_hello_to usage example is missing an underscore [Firas Alragom]:
def say_hello_to(name)
"Hello, #{name}!"
end
puts say_hello to "Hampton"
The last line should read:
puts say_hello_to("Hampton")
2nd paragraph, 3rd sentence: "The id fieldhas a type of integer;" should read "The id field has a type of integer;"
3rd bullet point under "Rails Blogs and Podcast": "A blog by Ryan Daigle called Rya's Scraps," should read "A blog by Ryan Daigle called Ryan's Scraps."
We use the pwd command on page 24 without explaining what it is, or what it does. Clarification is in order, then.
Unix is full of awesome little programs that "do one thing, and do it well." The pwd program is a good example. It stands for print working directory, and simply prints the name of the directory you're currently in to the screen.
The installation instructions for OS X state that you can reload a modified shell script (i.e., .profile) by opening a new terminal window. This works, but it seems hackish.
A better way is to use the source command to perform the reloading thusly:
$ source ~/.profile
We casually use the sudo command for the first time on page 24 without any explanation of what it is, or what it does. Allow us to clarify, then.
With great power comes great responsibility
What is sudo? The sudo command stands for "super user do." It allows you to execute a command as if you were the root user on the machine. Since the root user has permission to perform everything, you often use sudo to gain permission that your user lacks, for example, when you're installing software or working in directories other than your home directory.
The note on this page mentions Mongrel, but it's little more than a name drop. Mongrel is a high-performance HTTP server for Ruby applications. It's super popular, and most serious Rails setups are using it these days.
You install it as a Ruby gem:
sudo gem install -y mongrel
Once installed, the ./script/server command in Rails will launch a local Mongrel instance instead of WEBrick (or Lighttpd). The order of preference is as follows:
The controller generation example,
./script/generate controller salutation
works just fine, but the controller name really should have been plural. Rails is all about conventions, and there's a clear convention when it comes to controller names: they are plural.
In fact, on page 147 we've included a tip that clearly states:
It's a convention in Rails that controller names should always be plural.
If you're using the new(ish) map.resources feature that creates a set of RESTful routes, you'll know that plural controllers are the new black.
Note: If you're using Windows, you'll have to explicitly invoke the ruby interpreter by prefix your commands with ruby. Example:
C:\> ruby script\generate controller salutation
This applies for all commands in the book.
The note at the top of the page reads,
because Rails allows you to embed Ruby code in your HTML, you use the .rhtml (Ruby + HTML) extension for your templates.
This has since changed.
It started when the .rhtml extension was deprecated in favor of .erb, since it better describes the templating engine in use (ERb), and because embedded Ruby isn't limited to the generation of HTML alone.
We do mention this in the Note on page 149:
In edge-Rails,the .rhtml extension is deprecated in favor of .erb (for Embedded Ruby, or ERb). This isn't the case for the most recent stable version of Rails at the time of this writing (1.2.3), but it's something to keep an eye out for in the future. The .rhtml extension will still be supported for a long while and isn't scheduled to officially disappear until Rails 2.0.
This isn't 100% accurate either. Currently, Rails is now using the following naming convention for template files, in which it uses a mime-type to distinguish between templates for multiple request types:
#{filename}.#{mime-type}.#{template_handler}
Examples:
Under "Using Delete" ActiveRecord Callbacks are mentioned for the first time without any further explanation.
The delete family of methods differ from destroy in that they don't instantiate or perform callbacks on the object they're deleting. They remove the row immediately from the database.
The most succinct explanation comes from the Rails API:
Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic before or after an alteration of the object state. This can be used to make sure that associated and dependent objects are deleted when
destroyis called (by overwritingbefore_destroy) or to massage attributes before an object is created (by overwritingbefore_create).
See the documentation for ActiveRecord Callbacks for details.
On page 128 we refer to the hashed_password as being "encrypted," although this is technically incorrect.
Hashing takes any amount of data (binary or text) and creates a constant-length hash representing a checksum for that data. You can't decipher the original version from the hash -- it's one way only. Encryption, on the other hand, implies that the data can be restored, or, decrypted.
In Listings 6-14 and 6-23 (page 181), the create and login actions redirect to the events controller using the url_for syntax. Since we've already defined named routes for this, it would be a better idea to use them:
Instead of:
redirect_to :controller => 'events', :action => 'index'
Use:
redirect_to events_url
In Listing 6-23, we already set the @user variable equal to current_user in the update action (since we might need it if the update fails and needs to render the edit template with errors), so why not call update_attribtes on it instead of current_user?
@user = current_user
@user.update_attributes(params[:user])
Depending on your MySql installation, you might need to run the mysqlshow program as the root user. You can do this via the u option, e.g., mysqlshow -uroot.
In Listing 9-2, we create user fixtures in users.yml to test with, however our program expects the password to be hashed. How can we create a hashed password to enter into our fixtures? Well, there are a couple of ways to go about it.
You could create a new user (whose password will get hashed before being saved) and then look in the database to see the hashed version, or you can make use of the User#encrypt method to hash the given string.
To use the User#encrypt method, open up a console and type the following:
User.new.send(:encrypt, 'secret')
This will send the text 'secret' to the encrypt method. The result will be the hashed password.
Before we move on, let's clear something up here. Since encrypt is a private method, we can't call it directly. If you were to try User.new.encrypt('secret') you'd get a NoMethodError. To get around this, Ruby provides a way to expose private methods from the outside by way of the send method.
You can read more about send's behavior at: http://joshstaiger.org/archives/2006/12/the_ruby_send_h.html
Last updated: Wed Aug 13 14:43:49 -0400 2008