CS 240 Homework 4 - Rails

Due Sun Oct 12 at 11:59pm

Overview

In this assignment you will practice programming in Rails by adding a feature to an existing (simple) Rails app. You will also practice deploying the result publically on the Heroku cloud hosting service.

This homework involves modifying the textbook's example RottenPotatoes site in various ways. Git is your friend: practice working on a development branch, and commit frequently in case you accidently break something that previously worked! Storing lots of git commits makes it easy to back up to a previous version, or to compare what changed in each file since your last "good" commit.

Objectives

Necessary Files

You will want to get the starter code and instructions from the GitHub homework repository. Be sure and pull the latest version of the homework upstream repo, per the instructions in Hwk1. The starter code you're looking for is in the hwk4 folder.

You will need to run some commands to get the code setup:

Assignment Details

Part 1: Sorting The Movies

Your first enhancement to the RottenPotatoes app will be to make the movies sortable.

On the list of all movies page, the column headings for 'Movie Title' and 'Release Date' for a movie should be clickable links. Clicking one of them should cause the list to be reloaded but sorted in ascending order on that column. For example, clicking the 'release date' column heading should redisplay the list of movies with the earliest-released movies first; clicking the 'title' field should list the movies alphabetically by title. (For movies whose names begin with non-letters, the sort order should match the behavior of String#<=>)

Part 2: Filter the List of Movies

Your next enhancement will be to add some checkboxes that allow the user to filter the list to show only movies with certain MPAA ratings (see above screenshot). When the Refresh button is pressed, the list of movies is redisplayed showing only those movies whose ratings were checked.

This will require a couple of pieces of code. I've provided code that generates the checkboxes as a form, whcih you can include in the index.html.haml template:

= form_tag movies_path, :method => :get do
  Include:
  - @all_ratings.each do |rating|
    = rating
    = check_box_tag "ratings[#{rating}]"
  = submit_tag 'Refresh'

I highly recommend you take a few minutes to parse this code. What is it doing? How does it work? (These kinds of forms will be common and useful in your projects, so it's good to understand how they work!)

You will have to do some more work to use the above code: as you can see, it expects the variable @all_ratings to be an enumerable collection of all possible values of a movie rating, such as ['G','PG','PG-13','R']. The controller method needs to set up this variable. And since the possible values of movie ratings are really the responsibility of the Movie model, it’s best if the controller sets this variable by consulting the Model. Hence, you should create a class method of Movie that returns an appropriate value for this collection.

You will also need code that figures out (i) how to figure out which boxes the user checked and (ii) how to restrict the database query based on that result.

Regarding (i), try viewing the source of the movie listings with the checkbox form, and you’ll see that the checkboxes have field names like ratings[G], ratings[PG], etc. This trick will cause Rails to aggregate the values into a single hash called ratings, whose keys will be the names of the checked boxes only, and whose values will be the value attribute of the checkbox (which is “1” by default, since we didn’t specify another value when calling the check_box_tag helper). That is, if the user checks the ‘G’ and ‘R’ boxes, params will include as one if its values :ratings=>{"G"=>"1", "R"=>"1"}. Check out the Hash documentation for an easy way to grab just the keys of a hash, since we don’t care about the values in this case.

Regarding (ii), you’ll probably end up replacing Movie.all in the controller method with Movie.where or Movie.find, which have various options to help you restrict the database query.

Hints and caveats:

Part 3: Remembering the Sorting and Filtering Settings

The user can now click on the “Movie Title” or “Release Date” headings and see movies sorted by those columns, and can additionally use the checkboxes to restrict the listing to movies with certain ratings only. And we have preserved RESTfulness, because the URI itself always contains the parameters that will control sorting and filtering.

The last step is to remember these settings. That is, if the user has selected any combination of column sorting and restrict-by-rating constraints, and then the user clicks to see the details of one of the movies (for example), when she clicks the Back to Movie List on the detail page, the movie listing should “remember” the user’s sorting and filtering settings from before.

(Clicking away from the list to see the details of a movie is only one example; the settings should be remembered regardless what actions the user takes, so that any time she visits the index page, the settings are correctly reinstated.)

The best way to do the “remembering” will be to use the session[] hash. The session is like the flash[], except that once you set something in the session[] it is remembered "forever" until you clear the session with *cough* session.clear or selectively delete things from it with *cough* session.delete(:some_key). That way, in the index method, you can selectively apply the settings from the session[] even if the incoming URI doesn’t have the appropriate params[] set.

Hints and caveats:

Part 4: Deploy to Heroku

Really you can deploy to Heroku and test there at any time. However, Heroku may not provide as obvious errors (and is more difficult to deal with than local development), so I recommend you get things working "in development" and then deploy "to production" (so to speak).

If there are problems, you can find more details on Heroku in the appendices of the textbook.

Submitting

Make sure that your code passes all tests, and then push your code out to your personal homework repo (which you set you in Homework 1). You should include a README.md with a link to your Heroku installation.

Extensions

While they are not extra credit, there are a couple of follow-up assignments to this that give you more practice with Behavior-Driven Design (BDD), Cucumber, and Test-Driven Development. We will go over some of the first assignment in class as an example, but I leave the second to you if you want more practice. You can find starter code and instructions on the textbook's GitHub repos:

Grading

TBD...