Learn Enough to Be Dangerous
You have to make a choice. Choose...wisely.

Get occasional notifications about things like product discounts, blog posts, and new or updated tutorials. Unsubscribe at any time.

Gift Delivery Options
Quick Checkout
or Pay by Credit Card
Error processing your payment
  • You didn't choose whether or not to be added to the mailing list
Confirm
$0.00

Payments and credit card details are securely managed and protected by Learn Enough's payment processor, Stripe. More information on their site:

CART
Total
$0.00

Your Cart is Empty

$30
$300
$300
$XY
$XY
1234
  • Ruby on Rails (Rails 6)

Learn Enough Society

Certificate of Course Completion

This page certifies that mhartl has completed Ruby on Rails Tutorial! 🎉

About the tutorial
Since its initial publication in 2010, the Ruby on Rails Tutorial has been one of the leading introductions to web development. In this bestselling tutorial, you’ll learn how to develop and deploy real, industrial-strength web applications with Ruby on Rails, the open-source web framework that powers top websites such as Hulu, GitHub, Shopify, and Airbnb. This new 6th edition has been fully updated for Rails 6. Read full post
14 Dec 12:49, 2015
13 Aug 09:27, 2020
Exercise Answers
Exercise Question:
  • Using the range 0..16, print out the first 17 powers of 2.
  • mhartl's Answer:
    Exercise Question:
  • Define a method called yeller that takes in an array of characters and returns a string with an ALLCAPS version of the input. Verify that yeller(['o', 'l', 'd']) returns "OLD". Hint: Combine map, upcase, and join.
  • mhartl's Answer:
    Exercise Question:
  • Define a hash with symbol keys corresponding to name, email, and a “password digest”, and values equal to your name, your email address, and a random string of 16 lowercase letters.
  • mhartl's Answer:
    Exercise Question:
  • Per Table 5.1, change the route in Listing 5.41 to use signup_path instead of users_new_url.
  • mhartl's Answer:
    Exercise Question:
  • According to the default Rails page, what is the version of Ruby on your system? Confirm by running ruby -v at the command line.
  • mhartl's Answer:
    Exercise Question:
  • What is the version of Rails? Confirm that it matches the version installed in Listing 1.2.
  • mhartl's Answer:
    Exercise Question:
  • Change the content of the hello action in Listing 1.13 to read “hola, mundo!” instead of “hello, world!”.
  • mhartl's Answer:
    Exercise Question:
  • Show that Rails supports non-ASCII characters by including an inverted exclamation point, as in “¡Hola, mundo!” (Figure 1.21).15 To get a ¡ character on a Mac, you can use Option-1; otherwise, you can always copy-and-paste the character into your editor.
  • mhartl's Answer:
    Exercise Question:
  • By following the example of the hello action in Listing 1.13, add a second action called goodbye that renders the text “goodbye, world!”. Edit the routes file from Listing 1.15 so that the root route goes to goodbye instead of to hello (Figure 1.22).
  • mhartl's Answer:
    Exercise Question:
  • By making the same change as in Section 1.2.4.1, arrange for your production app to display “hola, mundo!”.
  • mhartl's Answer:
    Exercise Question:
  • As in Section 1.2.4.1, arrange for the root route to display the result of the goodbye action. When deploying, confirm that you can omit main in the Git push, as in git push heroku.
  • mhartl's Answer:
    Exercise Question:
  • Run heroku help to see a list of Heroku commands. (If the output of heroku help doesn’t fit in your terminal window, either scroll up or use heroku help | less to pipe to the less command.) What is the command to display logs for an app?
  • mhartl's Answer:
    Exercise Question:
  • Use the command identified in the previous exercise to inspect the activity on your application. What was the most recent event? (This command is often useful when debugging production apps.)
  • mhartl's Answer:
    Exercise Question:
  • (For readers who know CSS) Create a new user, then use your browser’s HTML inspector to determine the CSS id for the text “User was successfully created.” What happens when you refresh your browser?
  • mhartl's Answer:
    Exercise Question:
  • What happens if you try to create a user with a name but no email address?
  • mhartl's Answer:
    Exercise Question:
  • What happens if you try create a user with an invalid email address, like “@example.com”?
  • mhartl's Answer:
    Exercise Question:
  • Destroy each of the users created in the previous exercises. Does Rails display a message by default when a user is destroyed?
  • mhartl's Answer:
    Exercise Question:
  • By referring to Figure 2.12, write out the analogous steps for visiting the URL /users/1/edit.
  • mhartl's Answer:
    Exercise Question:
  • Find the line in the scaffolding code that retrieves the user from the database in the previous exercise. Hint: It’s in a special location called set_user.
  • mhartl's Answer:
    Exercise Question:
  • What is the name of the view file for the user edit page?
  • mhartl's Answer:
    Exercise Question:
  • (For readers who know CSS) Create a new micropost, then use your browser’s HTML inspector to determine the CSS id for the text “Micropost was successfully created.” What happens when you refresh your browser?
  • mhartl's Answer:
    Exercise Question:
  • Try to create a micropost with empty content and no user id.
  • mhartl's Answer:
    Exercise Question:
  • Try to create a micropost with over 140 characters of content (say, the first paragraph from the Wikipedia article on Ruby).
  • mhartl's Answer:
    Exercise Question:
  • Destroy the microposts from the previous exercises.
  • mhartl's Answer:
    Exercise Question:
  • Try to create a micropost with the same long content used in a previous exercise (Section 2.3.1.1). How has the behavior changed?
  • mhartl's Answer:
    Exercise Question:
  • (For readers who know CSS) Use your browser’s HTML inspector to determine the CSS id of the error message produced by the previous exercise.
  • mhartl's Answer:
    Exercise Question:
  • The code in Listing 2.18 shows how to add a validation for the presence of micropost content in order to ensure that microposts can’t be blank. Verify that you get the behavior shown in Figure 2.18.
  • mhartl's Answer:
    Exercise Question:
  • Update Listing 2.19 by replacing FILL_IN with the appropriate code to validate the presence of name and email attributes in the User model (Figure 2.19).
  • mhartl's Answer:
    Exercise Question:
  • By examining the contents of the Application controller file, find the line that causes ApplicationController to inherit from ActionController::Base.
  • mhartl's Answer:
    Exercise Question:
  • Is there an analogous file containing a line where ApplicationRecord inherits from ActiveRecord::Base? Hint: It would probably be a file called something like application_record.rb in the app/models directory.
  • mhartl's Answer:
    Exercise Question:
  • Create a few users on the production app.
  • mhartl's Answer:
    Exercise Question:
  • By trying to create a micropost with content over 140 characters, confirm that the validation from Listing 2.14 works on the production app.
  • mhartl's Answer:
    Exercise Question:
  • Create a few production microposts for the first user.
  • mhartl's Answer:
    Exercise Question:
  • Edit the user show page to display the content of the user’s first micropost. (Use your technical sophistication (Box 1.2) to guess the syntax based on the other content in the file.) Confirm by visiting /users/1 that it worked.
  • mhartl's Answer:
    Exercise Question:
  • Confirm that GitHub renders the Markdown for the README in Listing 3.3 as HTML (Figure 3.2).
  • mhartl's Answer:
    Exercise Question:
  • By visiting the root route on the production server, verify that the deployment to Heroku succeeded.
  • mhartl's Answer:
    Exercise Question:
  • Generate a controller called Foo with actions bar and baz.
  • mhartl's Answer:
    Exercise Question:
  • By applying the techniques described in Box 3.1, destroy the Foo controller and its associated actions.
  • mhartl's Answer:
    Exercise Question:
  • You may have noticed some repetition in the Static Pages controller test (Listing 3.26). In particular, the base title, “Ruby on Rails Tutorial Sample App”, is the same for every title test. Using the special function setup, which is automatically run before every test, verify that the tests in Listing 3.32 are still green. (Listing 3.32 uses an instance variable, seen briefly in Section 2.2.2 and covered further in Section 4.4.5, combined with string interpolation, which is covered further in Section 4.2.1.)
  • mhartl's Answer:
    Exercise Question:
  • Make a Contact page for the sample app.15 Following the model in Listing 3.17, first write a test for the existence of a page at the URL /static_pages/contact by testing for the title “Contact | Ruby on Rails Tutorial Sample App”. Get your test to pass by following the same steps as when making the About page in Section 3.3.3, including filling the Contact page with the content from Listing 3.42.
  • mhartl's Answer:
    Exercise Question:
  • Adding the root route in Listing 3.43 leads to the creation of a Rails helper called root_url (in analogy with helpers like static_pages_home_url). By filling in the code marked FILL_IN in Listing 3.44, write a test for the root route.
  • mhartl's Answer:
    Exercise Question:
  • Due to the code in Listing 3.43, the test in the previous exercise is already green. In such a case, it’s harder to be confident that we’re actually testing what we think we’re testing, so modify the code in Listing 3.43 by commenting out the root route to get to red (Listing 3.45). (We’ll talk more about Ruby comments in Section 4.2.) Then uncomment it (thereby restoring the original Listing 3.43) and verify that you get back to green.
  • mhartl's Answer:
    Exercise Question:
  • Assign variables city and state to your current city and state of residence. (If residing outside the U.S., substitute the analogous quantities.)
  • mhartl's Answer:
    Exercise Question:
  • Using interpolation, print (using puts) a string consisting of the city and state separated by a comma and a space, as in “Los Angeles, CA”.
  • mhartl's Answer:
    Exercise Question:
  • Repeat the previous exercise but with the city and state separated by a tab character.
  • mhartl's Answer:
    Exercise Question:
  • What is the result if you replace double quotes with single quotes in the previous exercise?
  • mhartl's Answer:
    Exercise Question:
  • What is the length of the string “racecar”?
  • mhartl's Answer:
    Exercise Question:
  • Confirm using the reverse method that the string in the previous exercise is the same when its letters are reversed.
  • mhartl's Answer:
    Exercise Question:
  • Assign the string “racecar” to the variable s. Confirm using the comparison operator == that s and s.reverse are equal.
  • mhartl's Answer:
    Exercise Question:
  • What is the result of running the code shown in Listing 4.9? How does it change if you reassign the variable s to the string “onomatopoeia”? Hint: Use up-arrow to retrieve and edit previous commands
  • mhartl's Answer:
    Exercise Question:
  • By replacing FILL_IN with the appropriate comparison test shown in Listing 4.10, define a method for testing palindromes. Hint: Use the comparison shown in Listing 4.9.
  • mhartl's Answer:
    Exercise Question:
  • By running your palindrome tester on “racecar” and “onomatopoeia”, confirm that the first is a palindrome and the second isn’t.
  • mhartl's Answer:
    Exercise Question:
  • By calling the nil? method on palindrome_tester("racecar"), confirm that its return value is nil (i.e., calling nil? on the result of the method should return true). This is because the code in Listing 4.10 prints its responses instead of returning them.
  • mhartl's Answer:
    Exercise Question:
  • Assign a to be to the result of splitting the string “A man, a plan, a canal, Panama” on comma-space.
  • mhartl's Answer:
    Exercise Question:
  • Assign s to the string resulting from joining a on nothing.
  • mhartl's Answer:
    Exercise Question:
  • Split s on whitespace and rejoin on nothing. Use the palindrome test from Listing 4.10 to confirm that the resulting string s is not a palindrome by the current definition. Using the downcase method, show that s.downcase is a palindrome.
  • mhartl's Answer:
    Exercise Question:
  • What is the result of selecting element 7 from the range of letters a through z? What about the same range reversed? Hint: In both cases you will have to convert the range to an array.
  • mhartl's Answer:
    Exercise Question:
  • Define a method called shuffled_subdomain that returns a string of eight letters from a fully shuffled alphabet.
  • mhartl's Answer:
    Exercise Question:
  • By replacing the question marks in Listing 4.12 with the appropriate methods, combine split, shuffle, and join to write a function that shuffles the letters in a given string.
  • mhartl's Answer:
    Exercise Question:
  • Define a hash with the keys 'one', 'two', and 'three', and the values 'uno', 'dos', and 'tres'. Iterate over the hash, and for each key–value pair print out "'#{key}' in Spanish is '#{value}'".
  • mhartl's Answer:
    Exercise Question:
  • Create three hashes called person1, person2, and person3, with first and last names under the keys :first and :last. Then create a params hash so that params[:father] is person1, params[:mother] is person2, and params[:child] is person3. Verify that, for example, params[:father][:first] has the right value.
  • mhartl's Answer:
    Exercise Question:
  • Find an online version of the Ruby API and read about the Hash method merge. What is the value of the following expression?
      { "a" => 100, "b" => 200 }.merge({ "b" => 300 })
    
  • mhartl's Answer:
    Exercise Question:
  • What is the literal constructor for the range of integers from 1 to 10?
  • mhartl's Answer:
    Exercise Question:
  • What is the constructor using the Range class and the new method? Hint: new takes two arguments in this context.
  • mhartl's Answer:
    Exercise Question:
  • Confirm using the == operator that the literal and named constructors from the previous two exercises are identical.
  • mhartl's Answer:
    Exercise Question:
  • What is the class hierarchy for a range? For a hash? For a symbol?
  • mhartl's Answer:
    Exercise Question:
  • Confirm that the method shown in Listing 4.15 works even if we replace self.reverse with just reverse.
  • mhartl's Answer:
    Exercise Question:
  • Verify that “racecar” is a palindrome and “onomatopoeia” is not. What about the name of the South Indian language “Malayalam”? Hint: Downcase it first.
  • mhartl's Answer:
    Exercise Question:
  • Using Listing 4.16 as a guide, add a shuffle method to the String class. Hint: Refer to Listing 4.12.
  • mhartl's Answer:
    Exercise Question:
  • Verify that Listing 4.16 works even if you remove self..
  • mhartl's Answer:
    Exercise Question:
  • By running the Rails console in the toy app’s directory from Chapter 2, confirm that you can create a user object using User.new.
  • mhartl's Answer:
    Exercise Question:
  • Determine the class hierarchy of the user object.
  • mhartl's Answer:
    Exercise Question:
  • In the example User class, change from name to separate first and last name attributes, and then add a method called full_name that returns the first and last names separated by a space. Use it to replace the use of name in the formatted email method.
  • mhartl's Answer:
    Exercise Question:
  • Verify that full_name.split is the same as alphabetical_name.split(', ').reverse.
  • mhartl's Answer:
    Exercise Question:
  • It’s well-known that no web page is complete without a cat image. Using the command in Listing 5.4, arrange to download the kitten pic shown in Figure 5.3.11
  • mhartl's Answer:
    Exercise Question:
  • Using the mv command, move kitten.jpg to the correct asset directory for images (Section 5.2.1).
  • mhartl's Answer:
    Exercise Question:
  • Using image_tag, add kitten.jpg to the Home page, as shown in Figure 5.4.
  • mhartl's Answer:
    Exercise Question:
  • Using code like that shown in Listing 5.10, comment out the cat image from Section 5.1.1.1. Verify using a web inspector that the HTML for the image no longer appears in the page source.
  • mhartl's Answer:
    Exercise Question:
  • By adding the CSS in Listing 5.11 to custom.scss, hide all images in the application—currently just the Rails logo on the Home page). Verify with a web inspector that, although the image doesn’t appear, the HTML source is still present. (Be sure to undo this exercise when you’re done so that future images display correctly.)
  • mhartl's Answer:
    Exercise Question:
  • Replace the default Rails head with the call to render shown in Listing 5.18. Hint: For convenience, cut the default header rather than just deleting it.
  • mhartl's Answer:
    Exercise Question:
  • Because we haven’t yet created the partial needed by Listing 5.18, the tests should be red. Confirm that this is the case.
  • mhartl's Answer:
    Exercise Question:
  • Create the necessary partial in the layouts directory, paste in the contents, and verify that the tests are now green again.
  • mhartl's Answer:
    Exercise Question:
  • As suggested in Section 5.2.2, go through the steps to convert the footer CSS from Listing 5.17 to Listing 5.20 to SCSS by hand.
  • mhartl's Answer:
    Exercise Question:
  • Add a method called alphabetical_name that returns the last name and first name separated by comma-space.
  • mhartl's Answer:
    Exercise Question:
  • It’s possible to use a named route other than the default using the as: option. Drawing inspiration from this famous Far Side comic strip, change the route for the Help page to use helf (Listing 5.29).
  • mhartl's Answer:
    Exercise Question:
  • Confirm that the tests are now red. Get them to green by updating the route in Listing 5.28.
  • mhartl's Answer:
    Exercise Question:
  • Revert the changes from these exercises using Undo.
  • mhartl's Answer:
    Exercise Question:
  • Update the layout links to use the helf route from Listing 5.29.
  • mhartl's Answer:
    Exercise Question:
  • Revert the changes using Undo.
  • mhartl's Answer:
    Exercise Question:
  • In the footer partial, change about_path to contact_path and verify that the tests catch the error.
  • mhartl's Answer:
    Exercise Question:
  • It’s convenient to use the full_title helper in the tests by including the Application helper into the test helper, as shown in Listing 5.35. We can then test for the right title using code like Listing 5.36. This is brittle, though, because now any typo in the base title (such as “Ruby on Rails Tutoial”) won’t be caught by the test suite. Fix this problem by writing a direct test of the full_title helper, which involves creating a file to test the application helper and then filling in the code indicated with FILL_IN in Listing 5.37. (Listing 5.37 uses assert_equal <expected>, <actual>, which verifies that the expected result matches the actual value when compared with the == operator.)
  • mhartl's Answer:
    Exercise Question:
  • The route in the previous exercise doesn’t yet exist, so confirm that the tests are now red. (This is intended to help us get comfortable with the red/green flow of Test Driven Development (TDD, Box 3.3); we’ll get the tests back to green in Section 5.4.2.)
  • mhartl's Answer:
    Exercise Question:
  • If you didn’t solve the exercise in Section 5.4.1.1, change the test in Listing 5.41 to use the named route signup_path. Because of the route defined in Listing 5.43, this test should initially be green.
  • mhartl's Answer:
    Exercise Question:
  • In order to verify the correctness of the test in the previous exercise, comment out the signup route to get to red, then uncomment to get to green.
  • mhartl's Answer:
    Exercise Question:
  • In the integration test from Listing 5.32, add code to visit the signup page using the get method and verify that the resulting page title is correct. Hint: Use the full_title helper as in Listing 5.36.
  • mhartl's Answer:
    Exercise Question:
  • Rails uses a file called schema.rb in the db/ directory to keep track of the structure of the database (called the schema, hence the filename). Examine your local copy of db/schema.rb and compare its contents to the migration code in Listing 6.2.
  • mhartl's Answer:
    Exercise Question:
  • Most migrations (including all the ones in this tutorial) are reversible, which means we can “migrate down” and undo them with a single command, called db:rollback:
      $ rails db:rollback
    
    After running this command, examine db/schema.rb to confirm that the rollback was successful. (See Box 3.1 for another technique useful for reversing migrations.) Under the hood, this command executes the drop_table command to remove the user table from the database. The reason this works is that the change method knows that drop_table is the inverse of create_table, which means that the rollback migration can be easily inferred. In the case of an irreversible migration, such as one to remove a database column, it is necessary to define separate up and down methods in place of the single change method. Read about migrations in the Rails Guides for more information.
  • mhartl's Answer:
    Exercise Question:
  • rerun the migration by executing rails db:migrate again. Confirm that the contents of db/schema.rb have been restored.
  • mhartl's Answer:
    Exercise Question:
  • In a Rails console, use the technique from Section 4.4.4 to confirm that User.new is of class User and inherits from ApplicationRecord.
  • mhartl's Answer:
    Exercise Question:
  • Confirm that ApplicationRecord inherits from ActiveRecord::Base.
  • mhartl's Answer:
    Exercise Question:
  • Confirm that user.name and user.email are of class String.
  • mhartl's Answer:
    Exercise Question:
  • Of what class are the created_at and updated_at attributes?
  • mhartl's Answer:
    Exercise Question:
  • Find the user by name. Confirm that find_by_name works as well. (You will often encounter this older style of find_by in legacy Rails applications.)
  • mhartl's Answer:
    Exercise Question:
  • For most practical purposes, User.all acts like an array, but confirm that in fact it’s of class User::ActiveRecord_Relation.
  • mhartl's Answer:
    Exercise Question:
  • Confirm that you can find the length of User.all by passing it the length method (Section 4.2.2). Ruby’s ability to manipulate objects based on how they act rather than on their formal class type is called duck typing, based on the aphorism that “If it looks like a duck, and it quacks like a duck, it’s probably a duck.”
  • mhartl's Answer:
    Exercise Question:
  • Update the user’s name using assignment and a call to save.
  • mhartl's Answer:
    Exercise Question:
  • Update the user’s email address using a call to update.
  • mhartl's Answer:
    Exercise Question:
  • Confirm that you can change the magic columns directly by updating the created_at column using assignment and a save. Use the value 1.year.ago, which is a Rails way to create a timestamp one year before the present time.
  • mhartl's Answer:
    Exercise Question:
  • In the console, confirm that a new user is currently valid.
  • mhartl's Answer:
    Exercise Question:
  • Confirm that the user created in Section 6.1.3 is also valid.
  • mhartl's Answer:
    Exercise Question:
  • Make a new user called u and confirm that it’s initially invalid. What are the full error messages?
  • mhartl's Answer:
    Exercise Question:
  • Confirm that u.errors.messages is a hash of errors. How would you access just the email errors?
  • mhartl's Answer:
    Exercise Question:
  • Make a new user with too-long name and email and confirm that it’s not valid.
  • mhartl's Answer:
    Exercise Question:
  • What are the error messages generated by the length validation?
  • mhartl's Answer:
    Exercise Question:
  • By pasting in the valid addresses from Listing 6.18 and invalid addresses from Listing 6.19 into the test string area at Rubular, confirm that the regex from Listing 6.21 matches all of the valid addresses and none of the invalid ones.
  • mhartl's Answer:
    Exercise Question:
  • As noted above, the email regex in Listing 6.21 allows invalid email addresses with consecutive dots in the domain name, i.e., addresses of the form [email protected]. Add this address to the list of invalid addresses in Listing 6.19 to get a failing test, and then use the more complicated regex shown in Listing 6.23 to get the test to pass.
  • mhartl's Answer:
    Exercise Question:
  • Add [email protected] to the list of addresses at Rubular, and confirm that the regex shown in Listing 6.23 matches all the valid addresses and none of the invalid ones.
  • mhartl's Answer:
    Exercise Question:
  • Add a test for the email downcasing from Listing 6.32, as shown in Listing 6.34. This test uses the reload method for reloading a value from the database and the assert_equal method for testing equality. To verify that Listing 6.34 tests the right thing, comment out the before_save line to get to red, then uncomment it to get to green.
  • mhartl's Answer:
    Exercise Question:
  • By running the test suite, verify that the before_save callback can be written using the “bang” method email.downcase! to modify the email attribute directly, as shown in Listing 6.35.
  • mhartl's Answer:
    Exercise Question:
  • Confirm that a user with valid name and email still isn’t valid overall.
  • mhartl's Answer:
    Exercise Question:
  • What are the error messages for a user with no password?
  • mhartl's Answer:
    Exercise Question:
  • Confirm that a user with valid name and email but a too-short password isn’t valid.
  • mhartl's Answer:
    Exercise Question:
  • What are the associated error messages?
  • mhartl's Answer:
    Exercise Question:
  • Quit and restart the console, and then find the user created in this section.
  • mhartl's Answer:
    Exercise Question:
  • Try changing the name by assigning a new name and calling save. Why didn’t it work?
  • mhartl's Answer:
    Exercise Question:
  • Update user’s name to use your name. Hint: The necessary technique is covered in Section 6.1.5.
  • mhartl's Answer:
    Exercise Question:
  • Add tests for the sidebar micropost count (including proper pluralization). Listing 13.60 will help get you started.
  • mhartl's Answer:
    Exercise Question:
  • Visit /about in your browser and use the debug information to determine the controller and action of the params hash.
  • mhartl's Answer:
    Exercise Question:
  • In the Rails console, pull the first user out of the database and assign it to the variable user. What is the output of puts user.attributes.to_yaml? Compare this to using the y method via y user.attributes.
  • mhartl's Answer:
    Exercise Question:
  • Using embedded Ruby, add the created_at and updated_at “magic column” attributes to the user show page from Listing 7.4.
  • mhartl's Answer:
    Exercise Question:
  • Using embedded Ruby, add Time.now to the user show page. What happens when you refresh the browser?
  • mhartl's Answer:
    Exercise Question:
  • With the debugger in the show action as in Listing 7.6, hit /users/1. Use puts to display the value of the YAML form of the params hash. Hint: Refer to the relevant exercise in Section 7.1.1.1. How does it compare to the debug information shown by the debug method in the site template?
  • mhartl's Answer:
    Exercise Question:
  • Put the debugger in the User new action and hit /users/new. What is the value of @user?
  • mhartl's Answer:
    Exercise Question:
  • Associate a Gravatar with your primary email address if you haven’t already. What is the MD5 hash associated with the image?
  • mhartl's Answer:
    Exercise Question:
  • Verify that the code in Listing 7.12 allows the gravatar_for helper defined in Section 7.1.4 to take an optional size parameter, allowing code like gravatar_for user, size: 50 in the view. (We’ll put this improved helper to use in Section 10.3.1.)
  • mhartl's Answer:
    Exercise Question:
  • The options hash used in the previous exercise is still commonly used, but as of Ruby 2.0 we can use keyword arguments instead. Confirm that the code in Listing 7.13 can be used in place of Listing 7.12. What are the diffs between the two?
  • mhartl's Answer:
    Exercise Question:
  • Confirm by replacing all occurrences of f with foobar that the name of the block variable is irrelevant as far as the result is concerned. Why might foobar nevertheless be a bad choice?
  • mhartl's Answer:
    Exercise Question:
  • Learn Enough HTML to Be Dangerous, in which all HTML is written by hand, doesn’t cover the form tag. Why not?
  • mhartl's Answer:
    Exercise Question:
  • By hitting the URL /signup?admin=1, confirm that the admin attribute appears in the params debug information.
  • mhartl's Answer:
    Exercise Question:
  • Confirm by changing the minimum length of passwords to 5 that the error message updates automatically as well.
  • mhartl's Answer:
    Exercise Question:
  • How does the URL on the unsubmitted signup form (Figure 7.13) compare to the URL for a submitted signup form (Figure 7.19)? Why don’t they match?
  • mhartl's Answer:
    Exercise Question:
  • Write a test for the error messages implemented in Listing 7.20. How detailed you want to make your tests is up to you; a suggested template appears in Listing 7.25.
  • mhartl's Answer:
    Exercise Question:
  • Using the Rails console, verify that a user is in fact created when submitting valid information.
  • mhartl's Answer:
    Exercise Question:
  • Confirm by updating Listing 7.26 and submitting a valid user that redirect_to user_url(@user) has the same effect as redirect_to @user.
  • mhartl's Answer:
    Exercise Question:
  • In the console, confirm that you can use interpolation (Section 4.2.1) to interpolate a raw symbol. For example, what is the return value of "#{:success}"?
  • mhartl's Answer:
    Exercise Question:
  • How does the previous exercise relate to the flash iteration shown in Listing 7.28?
  • mhartl's Answer:
    Exercise Question:
  • Using the Rails console, find by the email address to double-check that the new user was actually created. The result should look something like Listing 7.30.
  • mhartl's Answer:
    Exercise Question:
  • Create a new user with your primary email address. Verify that the Gravatar correctly appears.
  • mhartl's Answer:
    Exercise Question:
  • Write a test for the flash implemented in Section 7.4.2. How detailed you want to make your tests is up to you; a suggested ultra-minimalist template appears in Listing 7.32, which you should complete by replacing FILL_IN with the appropriate code. (Even testing for the right key, much less the text, is likely to be brittle, so I prefer to test only that the flash isn’t empty.)
  • mhartl's Answer:
    Exercise Question:
  • As noted above, the flash HTML in Listing 7.29 is ugly. Verify by running the test suite that the cleaner code in Listing 7.33, which uses the Rails content_tag helper, also works.
  • mhartl's Answer:
    Exercise Question:
  • Verify that the test fails if you comment out the redirect line in Listing 7.26.
  • mhartl's Answer:
    Exercise Question:
  • Suppose we changed @user.save to false in Listing 7.26. How does this change verify that the assert_difference block is testing the right thing?
  • mhartl's Answer:
    Exercise Question:
  • Confirm on your browser that the SSL lock and https appear.
  • mhartl's Answer:
    Exercise Question:
  • Create a user on the production site using your primary email address. Does your Gravatar appear correctly?
  • mhartl's Answer:
    Exercise Question:
  • What is the difference between GET login_path and POST login_path?
  • mhartl's Answer:
    Exercise Question:
  • By piping the results of rails routes to grep, list all the routes associated with the Users resource. Do the same for Sessions. How many routes does each resource have? Hint: Refer to the section on grep in Learn Enough Command Line to Be Dangerous.
  • mhartl's Answer:
    Exercise Question:
  • Submissions from the form defined in Listing 8.4 will be routed to the Session controller’s create action. How does Rails know to do this? Hint: Refer to Table 8.1 and the first line of Listing 8.5.
  • mhartl's Answer:
    Exercise Question:
  • Using the Rails console, confirm each of the values in Table 8.2. Start with user = nil, and then use user = User.first. Hint: To coerce the result to a boolean value, use the bang-bang trick from Section 4.2.2, as in !!(user && user.authenticate('foobar')).
  • mhartl's Answer:
    Exercise Question:
  • Verify in your browser that the sequence from Section 8.1.4 works correctly, i.e., that the flash message disappears when you click on a second page.
  • mhartl's Answer:
    Exercise Question:
  • Log in with a valid user and inspect your browser’s cookies. What is the value of the session content? Hint: If you don’t know how to view your browser’s cookies, Google for it (Box 1.2).
  • mhartl's Answer:
    Exercise Question:
  • What is the value of the Expires attribute from the previous exercise?
  • mhartl's Answer:
    Exercise Question:
  • Confirm at the console that User.find_by(id: ...) returns nil when the corresponding user doesn’t exist.
  • mhartl's Answer:
    Exercise Question:
  • In a Rails console, create a session hash with key :user_id. By following the steps in Listing 8.17, confirm that the ||= operator works as required.
  • mhartl's Answer:
    Exercise Question:
  • Using the cookie inspector in your browser (Section 8.2.1.1), remove the session cookie and confirm that the layout links revert to the non-logged-in state.
  • mhartl's Answer:
    Exercise Question:
  • Log in again, confirming that the layout links change correctly. Then quit your browser and start it again to confirm that the layout links revert to the non-logged-in state. (If your browser has a “remember where I left off” feature that automatically restores the session, be sure to disable it in this step (Box 1.2).)
  • mhartl's Answer:
    Exercise Question:
  • Is the test suite red or green if you comment out the log_in line in Listing 8.32?
  • mhartl's Answer:
    Exercise Question:
  • By using your text editor’s ability to comment out code, toggle back and forth between commenting out code in Listing 8.32 and confirm that the test suite toggles between red and green. (You will need to save the file between toggles.)
  • mhartl's Answer:
    Exercise Question:
  • Confirm in a browser that the “Log out” link causes the correct changes in the site layout. What is the correspondence between these changes and the final three steps in Listing 8.38?
  • mhartl's Answer:
    Exercise Question:
  • By checking the site cookies, confirm that the session is correctly removed after logging out.
  • mhartl's Answer:
    Exercise Question:
  • In the console, set user to the first user in the database, and verify by calling it directly that the remember method works. How do remember_token and remember_digest compare?
  • mhartl's Answer:
    Exercise Question:
  • In Listing 9.3, we defined the new token and digest class methods by explicitly prefixing them with User. This works fine and, because they are actually called using User.new_token and User.digest, it is probably the clearest way to define them. But there are two perhaps more idiomatically correct ways to define class methods, one slightly confusing and one extremely confusing. By running the test suite, verify that the implementations in Listing 9.4 (slightly confusing) and Listing 9.5 (extremely confusing) are correct. (Note that, in the context of Listing 9.4 and Listing 9.5, self is the User class, whereas the other uses of self in the User model refer to a user object instance. This is part of what makes them confusing.)
  • mhartl's Answer:
    Exercise Question:
  • By finding the cookie in your local browser, verify that a remember token and encrypted user id are present after logging in.
  • mhartl's Answer:
    Exercise Question:
  • At the console, verify directly that the authenticated? method defined in Listing 9.6 works correctly.
  • mhartl's Answer:
    Exercise Question:
  • After logging out, verify that the corresponding cookies have been removed from your browser.
  • mhartl's Answer:
    Exercise Question:
  • Comment out the fix in Listing 9.16 and then verify that the first subtle bug is present by opening two logged-in tabs, logging out in one, and then clicking “Log out” link in the other.
  • mhartl's Answer:
    Exercise Question:
  • Comment out the fix in Listing 9.19 and verify that the second subtle bug is present by logging out in one browser and closing and opening the second browser.
  • mhartl's Answer:
    Exercise Question:
  • Uncomment the fixes and confirm that the test suite goes from red to green.
  • mhartl's Answer:
    Exercise Question:
  • By inspecting your browser’s cookies directly, verify that the “remember me” checkbox is having its intended effect.
  • mhartl's Answer:
    Exercise Question:
  • At the console, invent examples showing both possible behaviors of the ternary operator (Box 9.2).
  • mhartl's Answer:
    Exercise Question:
  • As mentioned above, the application currently doesn’t have any way to access the virtual remember_token attribute in the integration test in Listing 9.25. It is possible, though, using a special test method called assigns. Inside a test, you can access instance variables defined in the controller by using assigns with the corresponding symbol. For example, if the create action defines an @user variable, we can access it in the test using assigns(:user). Right now, the Sessions controller create action defines a normal (non-instance) variable called user, but if we change it to an instance variable we can test that cookies correctly contains the user’s remember token. By filling in the missing elements in Listing 9.27 and Listing 9.28 (indicated with question marks ? and FILL_IN), complete this improved test of the “remember me” checkbox.
  • mhartl's Answer:
    Exercise Question:
  • Verify by removing the authenticated? expression in Listing 9.33 that the second test in Listing 9.31 fails, thereby confirming that it tests the right thing.
  • mhartl's Answer:
    Exercise Question:
  • As noted above, there’s a minor security issue associated with using target="_blank" to open URLs, which is that the target site gains control of what’s known as the “window object” associated with the HTML document. The result is that the target site could potentially introduce malicious content, such as a phishing page. This is extremely unlikely to happen when linking to a reputable site like Gravatar, but it turns out that we can eliminate the risk entirely by setting the rel attribute (“relationship”) to "noopener" in the origin link. Add this attribute to the Gravatar edit link in Listing 10.2.
  • mhartl's Answer:
    Exercise Question:
  • Remove the duplicated form code by refactoring the new.html.erb and edit.html.erb views to use the partial in Listing 10.5, as shown in Listing 10.6 and Listing 10.7. Note the use of the provide method, which we used before in Section 3.4.3 to eliminate duplication in the layout.3
  • mhartl's Answer:
    Exercise Question:
  • Confirm by submitting various invalid combinations of username, email, and password that the edit form won’t accept invalid submissions.
  • mhartl's Answer:
    Exercise Question:
  • Add a line in Listing 10.9 to test for the correct number of error messages. Hint: Use an assert_select (Table 5.2) that tests for a div with class alert containing the text “The form contains 4 errors.”
  • mhartl's Answer:
    Exercise Question:
  • Double-check that you can now make edits by making a few changes on the development version of the application.
  • mhartl's Answer:
    Exercise Question:
  • What happens when you change the email address to one without an associated Gravatar?
  • mhartl's Answer:
    Exercise Question:
  • As noted above, by default before filters apply to every action in a controller, which in our cases is an error (requiring, e.g., that users log in to hit the signup page, which is absurd). By commenting out the only: hash in Listing 10.15, confirm that the test suite catches this error.
  • mhartl's Answer:
    Exercise Question:
  • Why is it important to protect both the edit and update actions?
  • mhartl's Answer:
    Exercise Question:
  • Which action could you more easily test in a browser?
  • mhartl's Answer:
    Exercise Question:
  • Write a test to make sure that friendly forwarding only forwards to the given URL the first time. On subsequent login attempts, the forwarding URL should revert to the default (i.e., the profile page). Hint: Add to the test in Listing 10.29 by checking for the right value of session[:forwarding_url].
  • mhartl's Answer:
    Exercise Question:
  • Put a debugger (Section 7.1.3) in the Sessions controller’s new action, then log out and try to visit /users/1/edit. Confirm in the debugger that the value of session[:forwarding_url] is correct. What is the value of request.get? for the new action? (Sometimes the terminal can freeze up or act strangely when you’re using the debugger; use your technical sophistication (Box 1.2) to resolve any issues.)
  • mhartl's Answer:
    Exercise Question:
  • We’ve now filled in all the links in the site layout. Write an integration test for all the layout links, including the proper behavior for logged-in and non-logged-in users. Hint: Use the log_in_as helper and add to the steps shown in Listing 5.32.
  • mhartl's Answer:
    Exercise Question:
  • Verify that trying to visit the edit page of another user results in a redirect as required by Section 10.2.2.
  • mhartl's Answer:
    Exercise Question:
  • Confirm at the console that setting the page to nil pulls out the first page of users.
  • mhartl's Answer:
    Exercise Question:
  • What is the Ruby class of the pagination object? How does it compare to the class of User.all?
  • mhartl's Answer:
    Exercise Question:
  • By commenting out the pagination links in Listing 10.45, confirm that the test in Listing 10.48 goes red.
  • mhartl's Answer:
    Exercise Question:
  • Confirm that commenting out only one of the calls to will_paginate leaves the tests green. How would you test for the presence of both sets of will_paginate links? Hint: Use a count from Table 5.2.
  • mhartl's Answer:
    Exercise Question:
  • Comment out the render line in Listing 10.52 and confirm that the resulting tests are red.
  • mhartl's Answer:
    Exercise Question:
  • By issuing a PATCH request directly to the user path as shown in Listing 10.56, verify that the admin attribute isn’t editable through the web. To be sure your test is covering the right thing, your first step should be to add admin to the list of permitted parameters in user_params so that the initial test is red. For the final line, make sure to load the updated user information from the database (Section 6.1.5).
  • mhartl's Answer:
    Exercise Question:
  • As the admin user, destroy a few sample users through the web interface. What are the corresponding entries in the server log?
  • mhartl's Answer:
    Exercise Question:
  • By commenting out the admin user before filter in Listing 10.59, confirm that the tests go red.
  • mhartl's Answer:
    Exercise Question:
  • Verify that the test suite is still green.
  • mhartl's Answer:
    Exercise Question:
  • Why does Table 11.2 list the _url form of the named route instead of the _path form? Hint: We’re going to use it in an email.
  • mhartl's Answer:
    Exercise Question:
  • Verify that the test suite is still green after the changes made in this section.
  • mhartl's Answer:
    Exercise Question:
  • By instantiating a User object in the console, confirm that calling the create_activation_digest method raises a NoMethodError due to its being a private method. What is the value of the user’s activation digest?
  • mhartl's Answer:
    Exercise Question:
  • In Listing 6.35, we saw that email downcasing can be written more simply as email.downcase! (without any assignment). Make this change to the downcase_email method in Listing 11.3 and verify by running the test suite that it works.
  • mhartl's Answer:
    Exercise Question:
  • At the console, verify that the escape method in the CGI module escapes out the email address as shown in Listing 11.15. What is the escaped value of the string "Don't panic!"?
  • mhartl's Answer:
    Exercise Question:
  • Preview the email templates in your browser. What do the Date fields read for your previews?
  • mhartl's Answer:
    Exercise Question:
  • Verify that the full test suite is still green.
  • mhartl's Answer:
    Exercise Question:
  • Confirm that the test goes red if you remove the call to CGI.escape in Listing 11.20.
  • mhartl's Answer:
    Exercise Question:
  • Sign up as a new user and verify that you’re properly redirected. What is the content of the generated email in the server log? What is the value of the activation token?
  • mhartl's Answer:
    Exercise Question:
  • Verify at the console that the new user has been created but that it is not yet activated.
  • mhartl's Answer:
    Exercise Question:
  • Create and remember a new user at the console. What are the user’s remember and activation tokens? What are the corresponding digests?
  • mhartl's Answer:
    Exercise Question:
  • Using the generalized authenticated? method from Listing 11.26, verify that the user is authenticated according to both the remember token and the activation token.
  • mhartl's Answer:
    Exercise Question:
  • Paste in the URL from the email generated in Section 11.2.4. What is the activation token?
  • mhartl's Answer:
    Exercise Question:
  • Verify at the console that the user is authenticated according to the activation token in the URL from the previous exercise. Is the user now activated?
  • mhartl's Answer:
    Exercise Question:
  • In Listing 11.35, the activate method makes two calls to the update_attribute, each of which requires a separate database transaction. By filling in the template shown in Listing 11.39, replace the two update_attribute calls with a single call to update_columns, which hits the database only once. (Note that, like update_attribute, update_columns doesn’t run the model callbacks or validations.) After making the changes, verify that the test suite is still green.
  • mhartl's Answer:
    Exercise Question:
  • Right now all users are displayed on the user index page at /users and are visible via the URL /users/:id, but it makes sense to show users only if they are activated. Arrange for this behavior by filling in the template shown in Listing 11.40.9 (This template uses the Active Record where method, which we’ll learn more about in Section 13.3.3.)
  • mhartl's Answer:
    Exercise Question:
  • Sign up for a new account in production. Did you get the email?
  • mhartl's Answer:
    Exercise Question:
  • Click on the link in the activation email to confirm that it works. What is the corresponding entry in the server log? Hint: Run heroku logs at the command line.
  • mhartl's Answer:
    Exercise Question:
  • To test the code in the previous exercise, write integration tests for both /users and /users/:id. A template for a suggested /users test is shown in Listing 11.41. For /users/:id, you should run rails generate integration_test user_show and then add an inactive fixture user as shown in Listing 11.42. A template for the corresponding test is shown in Listing 11.43.
  • mhartl's Answer:
    Exercise Question:
  • Verify that the test suite is still green.
  • mhartl's Answer:
    Exercise Question:
  • Why does Table 12.1 list the _url form of the edit named route instead of the _path form? Hint: The answer is the same as for the similar account activations exercise (Section 11.1.1.1).
  • mhartl's Answer:
    Exercise Question:
  • Why does the form_with in Listing 12.4 use :password_reset instead of @password_reset?
  • mhartl's Answer:
    Exercise Question:
  • Submit a valid email address to the form shown in Figure 12.6. What error message do you get?
  • mhartl's Answer:
    Exercise Question:
  • Confirm at the console that the user in the previous exercise has valid reset_digest and reset_sent_at attributes, despite the error. What are the attribute values?
  • mhartl's Answer:
    Exercise Question:
  • Preview the email templates in your browser. What do the Date fields read for your previews?
  • mhartl's Answer:
    Exercise Question:
  • Submit a valid email address to the new password reset form. What is the content of the generated email in the server log?
  • mhartl's Answer:
    Exercise Question:
  • At the console, find the user object corresponding to the email address from the previous exercise and verify that it has valid reset_digest and reset_sent_at attributes.
  • mhartl's Answer:
    Exercise Question:
  • Run just the mailer tests. Are they green?
  • mhartl's Answer:
    Exercise Question:
  • Confirm that the test goes red if you remove the second call to CGI.escape in Listing 12.12.
  • mhartl's Answer:
    Exercise Question:
  • Follow the link in the email from the server log in Section 12.2.1.1. Does it properly render the form as shown in Figure 12.11?
  • mhartl's Answer:
    Exercise Question:
  • What happens if you submit the form from the previous exercise?
  • mhartl's Answer:
    Exercise Question:
  • Follow the email link from Section 12.2.1.1 again and submit mismatched passwords to the form. What is the error message?
  • mhartl's Answer:
    Exercise Question:
  • In the console, find the user belonging to the email link, and retrieve the value of the password_digest attribute. Now submit valid matching passwords to the form shown in Figure 12.12. Did the submission appear to work? How did it affect the value of password_digest? Hint: Use user.reload to retrieve the new value.
  • mhartl's Answer:
    Exercise Question:
  • Sign up for a new account in production. Did you get the email?
  • mhartl's Answer:
    Exercise Question:
  • Click on the link in the activation email to confirm that it works. What is the corresponding entry in the server log? Hint: Run heroku logs at the command line.
  • mhartl's Answer:
    Exercise Question:
  • Are you able to successfully update your password?
  • mhartl's Answer:
    Exercise Question:
  • In Listing 12.6, the create_reset_digest method makes two calls to update_attribute, each of which requires a separate database operation. By filling in the template shown in Listing 12.21, replace the two update_attribute calls with a single call to update_columns, which hits the database only once. After making the changes, verify that the test suite is still green. (For convenience, Listing 12.21 includes the results of solving the exercise in Listing 11.39.)
  • mhartl's Answer:
    Exercise Question:
  • Write an integration test for the expired password reset branch in Listing 12.16 by filling in the template shown in Listing 12.22. (This code introduces response.body, which returns the full HTML body of the page.) There are many ways to test for the result of an expiration, but the method suggested by Listing 12.22 is to (case-insensitively) check that the response body includes the word “expired”.
  • mhartl's Answer:
    Exercise Question:
  • Expiring password resets after a couple of hours is a nice security precaution, but there is an even more secure solution for cases where a public computer is used. The reason is that the password reset link remains active for 2 hours and can be used even if logged out. If a user reset their password from a public machine, anyone could press the back button and change the password (and get logged in to the site). To fix this, add the code shown in Listing 12.23 to clear the reset digest on successful password update.5
  • mhartl's Answer:
    Exercise Question:
  • Add a line to Listing 12.19 to test for the clearing of the reset digest in the previous exercise. Hint: Combine assert_nil (first seen in Listing 9.25) with user.reload (Listing 11.33) to test the reset_digest attribute directly.
  • mhartl's Answer:
    Exercise Question:
  • Using Micropost.new in the console, instantiate a new Micropost object called micropost with content “Lorem ipsum” and user id equal to the id of the first user in the database. What are the values of the magic columns created_at and updated_at?
  • mhartl's Answer:
    Exercise Question:
  • What is micropost.user for the micropost in the previous exercise? What about micropost.user.name?
  • mhartl's Answer:
    Exercise Question:
  • Save the micropost to the database. What are the values of the magic columns now?
  • mhartl's Answer:
    Exercise Question:
  • At the console, instantiate a micropost with no user id and blank content. Is it valid? What are the full error messages?
  • mhartl's Answer:
    Exercise Question:
  • At the console, instantiate a second micropost with no user id and content that’s too long. Is it valid? What are the full error messages?
  • mhartl's Answer:
    Exercise Question:
  • Set user to the first user in the database. What happens when you execute the command micropost = user.microposts.create(content: "Lorem ipsum")?
  • mhartl's Answer:
    Exercise Question:
  • The previous exercise should have created a micropost in the database. Confirm this by running user.microposts.find(micropost.id). What if you write micropost instead of micropost.id?
  • mhartl's Answer:
    Exercise Question:
  • What is the value of user == micropost.user? How about user.microposts.first == micropost?
  • mhartl's Answer:
    Exercise Question:
  • How does the value of Micropost.first.created_at compare to Micropost.last.created_at?
  • mhartl's Answer:
    Exercise Question:
  • What are the SQL queries for Micropost.first and Micropost.last? Hint: They are printed out by the console.
  • mhartl's Answer:
    Exercise Question:
  • Let user be the first user in the database. What is the id of its first micropost? Destroy the first user in the database using the destroy method, then confirm using Micropost.find that the user’s first micropost was also destroyed.
  • mhartl's Answer:
    Exercise Question:
  • What is the result of helper.time_ago_in_words(1.year.ago)?
  • mhartl's Answer:
    Exercise Question:
  • What is the Ruby class for a page of microposts? Hint: Use the code in Listing 13.23 as your model, and call the class method on paginate with the argument page: nil.
  • mhartl's Answer:
    Exercise Question:
  • See if you can guess the result of running (1..10).to_a.take(6). Check at the console to see if your guess is right.
  • mhartl's Answer:
    Exercise Question:
  • Is the to_a method in the previous exercise necessary?
  • mhartl's Answer:
    Exercise Question:
  • Faker has a huge number of occasionally amusing applications. By consulting the Faker documentation, learn how to print out a fake university name, a fake phone number, a fake Hipster Ipsum sentence, and a fake Chuck Norris fact.
  • mhartl's Answer:
    Exercise Question:
  • Comment out the application code needed to change the two 'h1' lines in Listing 13.28 from green to red.
  • mhartl's Answer:
    Exercise Question:
  • Update Listing 13.28 to test that will_paginate appears only once. Hint: Refer to Table 5.2.
  • mhartl's Answer:
    Exercise Question:
  • Why is it a bad idea to leave a copy of logged_in_user in the Users controller?
  • mhartl's Answer:
    Exercise Question:
  • Refactor the Home page to use separate partials for the two branches of the if-else statement.
  • mhartl's Answer:
    Exercise Question:
  • Use the newly created micropost UI to create the first real micropost. What are the contents of the INSERT command in the server log?
  • mhartl's Answer:
    Exercise Question:
  • In the console, set user to the first user in the database. Confirm that the values of Micropost.where("user_id = ?", user.id), user.microposts, and user.feed are all the same. Hint: It’s probably easiest to compare directly using ==.
  • mhartl's Answer:
    Exercise Question:
  • Create a new micropost and then delete it. What are the contents of the DELETE command in the server log?
  • mhartl's Answer:
    Exercise Question:
  • Confirm directly in the browser that the line redirect_to request.referrer || root_url can be replaced with the line redirect_back(fallback_location: root_url). (This method was added in Rails 5.)
  • mhartl's Answer:
    Exercise Question:
  • For each of the four scenarios indicated by comments in Listing 13.58 (starting with “Invalid submission”), comment out the application code to get the corresponding test to red, then uncomment to get back to green.
  • mhartl's Answer:
    Exercise Question:
  • Upload a micropost with attached image. Does the result look too big? (If so, don’t worry; we’ll fix it in Section 13.4.3.)
  • mhartl's Answer:
    Exercise Question:
  • Following the template in Listing 13.66, write a test of the image uploader in Section 13.4. As preparation, you should add an image to the fixtures directory using Listing 13.65. (You should type the backslash character \ in Listing 13.65, which is a line continuation character, but not the right angle bracket >, which should automatically be added by your terminal’s shell program.) The additional assertions in Listing 13.66 check both for a file upload field on the Home page and for a valid image attribute on the micropost resulting from valid submission. Note the use of the special fixture_file_upload method for uploading files as fixtures inside tests.20 Hint: To check for a valid image attribute, use the assigns method mentioned in Section 11.3.3 to access the micropost in the create action after valid submission.
  • mhartl's Answer:
    Exercise Question:
  • What happens if you try uploading an image bigger than 5 megabytes?
  • mhartl's Answer:
    Exercise Question:
  • What happens if you try uploading a file with an invalid extension?
  • mhartl's Answer:
    Exercise Question:
  • Upload a large image and confirm directly that the resizing is working. Does the resizing work even if the image isn’t square?
  • mhartl's Answer:
    Exercise Question:
  • Upload a large image and confirm directly that the resizing is working in production. Does the resizing work even if the image isn’t square?
  • mhartl's Answer:
    Exercise Question:
  • For the user with id equal to 1 from Figure 14.7, what would the value of user.following.map(&:id) be? (Recall the map(&:method_name) pattern from Section 4.3.2; user.following.map(&:id) just returns the array of ids.)
  • mhartl's Answer:
    Exercise Question:
  • By referring again to Figure 14.7, determine the ids of user.following for the user with id equal to 2. What would the value of user.following.map(&:id) be for this user?
  • mhartl's Answer:
    Exercise Question:
  • Using the create method from Table 14.1 in the console, create an active relationship for the first user in the database where the followed id is the second user.
  • mhartl's Answer:
    Exercise Question:
  • Confirm that the values for active_relationship.followed and active_relationship.follower are correct.
  • mhartl's Answer:
    Exercise Question:
  • Verify by commenting out the validations in Listing 14.5 that the tests still pass. (This is a change as of Rails 5, and in previous versions of Rails the validations are required. We’ll plan to leave them in for completeness, but it’s worth bearing in mind that you may see these validations omitted in other people’s code.)
  • mhartl's Answer:
    Exercise Question:
  • At the console, replicate the steps shown in Listing 14.9.
  • mhartl's Answer:
    Exercise Question:
  • What is the SQL for each of the commands in the previous exercise?
  • mhartl's Answer:
    Exercise Question:
  • At the console, create several followers for the first user in the database (which you should call user). What is the value of user.followers.map(&:id)?
  • mhartl's Answer:
    Exercise Question:
  • Confirm that user.followers.count matches the number of followers you created in the previous exercise.
  • mhartl's Answer:
    Exercise Question:
  • What is the SQL used by user.followers.count? How is this different from user.followers.to_a.count? Hint: Suppose that the user had a million followers.
  • mhartl's Answer:
    Exercise Question:
  • Using the console, confirm that User.first.followers.count matches the value expected from Listing 14.14.
  • mhartl's Answer:
    Exercise Question:
  • Confirm that User.first.following.count is correct as well.
  • mhartl's Answer:
    Exercise Question:
  • Verify that /users/2 has a follow form and that /users/5 has an unfollow form. Is there a follow form on /users/1?
  • mhartl's Answer:
    Exercise Question:
  • Confirm in the browser that the stats appear correctly on the Home page and on the profile page.
  • mhartl's Answer:
    Exercise Question:
  • Write tests for the stats on the Home page. Hint: Add to the test in Listing 13.28. Why don’t we also have to test the stats on the profile page?
  • mhartl's Answer:
    Exercise Question:
  • Verify in a browser that /users/1/followers and /users/1/following work. Do the image links in the sidebar work as well?
  • mhartl's Answer:
    Exercise Question:
  • Comment out the application code needed to turn the assert_select tests in Listing 14.29 red to confirm they’re testing the right thing.
  • mhartl's Answer:
    Exercise Question:
  • Follow and unfollow /users/2 through the web. Did it work?
  • mhartl's Answer:
    Exercise Question:
  • According to the server log, which templates are rendered in each case?
  • mhartl's Answer:
    Exercise Question:
  • Unfollow and refollow /users/2 through the web. Did it work?
  • mhartl's Answer:
    Exercise Question:
  • According to the server log, which templates are rendered in each case?
  • mhartl's Answer:
    Exercise Question:
  • By commenting and uncommenting each of the lines in the respond_to blocks (Listing 14.36), verify that the tests are testing the right things. Which test fails in each case?
  • mhartl's Answer:
    Exercise Question:
  • What happens if you delete one of the occurrences of xhr: true in Listing 14.40? Explain why this is a problem, and why the procedure in the previous exercise would catch it.
  • mhartl's Answer:
    Exercise Question:
  • Assuming the micropost’s ids are numbered sequentially, with larger numbers being more recent, what would user.feed.map(&:id) return for the feed shown in Figure 14.22? Hint: Recall the default scope from Section 13.1.4.
  • mhartl's Answer:
    Exercise Question:
  • In Listing 14.44, remove the part of the query that finds the user’s own posts. Which test in Listing 14.42 breaks?
  • mhartl's Answer:
    Exercise Question:
  • In Listing 14.44, remove the part of the query that finds the followed users’ posts. Which test in Listing 14.42 breaks?
  • mhartl's Answer:
    Exercise Question:
  • How could you change the query in Listing 14.44 to have the feed erroneously return microposts of unfollowed users, thereby breaking the third test in Listing 14.42? Hint: Returning all the microposts would do the trick.
  • mhartl's Answer:
    Exercise Question:
  • Write an integration test to verify that the first page of the feed appears on the Home page as required. A template appears in Listing 14.51.
  • mhartl's Answer:
    Exercise Question:
  • Note that Listing 14.51 escapes the expected HTML using CGI.escapeHTML (which is closely related to the CGI.escape method we used in Section 11.2.3 to escape URLs). Why is escaping the HTML necessary in this case? Hint: Try removing the escaping and carefully inspect the page source for the micropost content that doesn’t match. Using the search feature of your terminal shell (Cmd-F on Ctrl-F on most systems) to find the word “sorry” may prove particularly helpful.
  • mhartl's Answer:
    Exercise Question:
  • The code in Listing 14.47 can be expressed directly in Rails using a so-called left outer join using the left_outer_joins method. By running the tests, show that the code in Listing 14.52 returns a passing feed.12 Unfortunately, the actual feed contains multiple copies of the user’s own microposts (Figure 14.25),13 so use the test in Listing 14.53 to catch this error (using the distinct method, which returns the distinct elements in a collection). Then show that appending the distinct method to the query (Listing 14.54) results in a green test. By inspecting the generated SQL directly, confirm that the word DISTINCT appears in the query itself, indicating that the distinct elements are efficiently selected in the database rather than in our application’s memory. (Hint: To get the SQL, run User.first.feed in the Rails console.)
  • mhartl's Answer:
    Exercise Question:
  • Confirm by commenting out everything after if user in Line 8 of Listing 8.15 that the tests still pass even if we don’t authenticate the user by email and password, as shown in Listing 8.29. This is because Listing 8.9 doesn’t test the case of a correct user email but incorrect password. Fix this serious omission in our test suite by adding a valid email to the Users login test (Listing 8.30). Verify that the tests are red, then remove the Line 8 comment to get back to green. (Because it’s so important, we’ll add this test to the main code in Section 8.3.)
  • mhartl's Answer:
    Exercise Question:
  • Use the “safe navigation” operator &. to simplify the boolean test in Line 8 of Listing 8.15, as shown in Line 8 of Listing 8.31.16 This Ruby feature allows us to condense the common pattern of obj && obj.method into obj&.method. Confirm that the tests in Listing 8.30 still pass after the change.
  • mhartl's Answer:
    Exercise Question:
  • In Section 9.3.2.1, we implemented a session token to guard against session hijacking (Section 9.1.1). One likely scenario for users unfortunate enough to have sessions stolen would be to immediately reset their passwords. As a result, it would be especially nice if password reset automatically expired any such hijacked sessions. In Listing 12.18, FILL_IN the code needed to accomplish this. Hint: Recall from Listing 9.36 that we reused the remember digest as a session token, and the User model already has a method designed to delete this (Listing 9.11).
  • mhartl's Answer:
    Exercise Question:
  • As discussed in Section 9.1.1, the user_id in our application’s session is currently vulnerable to session replay attacks. Remedy this situation by using the code in Listing 9.35 and Listing 9.36 to FILL_IN the missing code in Listing 9.37. Hint: Set @current_user only if the token in the session hash is equal to the user’s session token. Note that, since the remember_digest is already a unique value tied to each user, we simply reuse it as a session token, generating one if it doesn’t already exist. (This involves a minor modification to the remember method to return the digest rather than returning the result of update_attribute, as seen in Listing 9.36. It’s safe to reuse the remember digest for this purpose both because bcrypt digests are secure by design and because session values are encrypted in any case (Section 8.2).) With this implementation, all that is needed to expire a hijacked session is to call user.forget. We’ll apply this method in Section 12.3.2.1 to ensure that resetting user passwords expires any existing sessions. Finally, because this code is security-related, it will be incorporated into future code listings and the sample app, unlike the solutions to other exercises in the tutorial.
  • mhartl's Answer:

    Join the Mailing List

    Get occasional notifications about things like product discounts, blog posts, and new or updated tutorials. Unsubscribe at any time.