Rotten Potatoes Setup

> cd Documents > rails new myrottenpotatoes -T

Make sure it completed correctly. Some users have reported needing to install additional items such as:

> gem install arel

> cd myrottenpotatoes; ls > gedit Gemfile &

Add the following lines not in a group (http://pastebin.com/86zGGRVU):

# use Haml for templates gem 'haml' # use Ruby debugger group :development, :test do gem 'debugger' end

> bundle install --without production > rails server

Open a browser & navigate to http://localhost:3000/movies You will see an error Open another terminal tab

> rake routes > gedit log/development.log &

Keep an eye on this file to see what’s happening in your application.

> gedit config/routes.rb &

Replace contents with (http://pastebin.com/piLDY4eM):

Myrottenpotatoes::Application.routes.draw do resources :movies root :to => redirect('/movies') end

> rm public/index. > rake routes > rails generate migration create_movies > ls db/migrate/ > gedit db/migrate/*_create_movies.rb &

Paste (http://pastebin.com/tmSkQX8b):

class CreateMovies < ActiveRecord::Migration def up create_table 'movies' do |t| t.string 'title' t.string 'rating' t.text 'description' t.datetime 'release_date' # Add fields that let Rails automatically keep track # of when movies are added or modified: t.timestamps end end

def down drop_table 'movies' # deletes the whole table and all its data! end end

Perform the database migration as follows.

> rake db:migrate

You can undo the last database migration with the command rake db:rollback to undo .

Open in your editor the class app/models/movie.rb and add the following code:

class Movie < ActiveRecord::Base def self.all_ratings ; %w[G PG PG13 R NC-17] ; end end

Back in main rails server tab, hit ctrl-c and run

> rails console > Movie.all Let’s seed some movies by going to a new terminal window:

> gedit db/seeds.rb &

Paste the following (http://pastebin.com/hNB7kpWz):

# Seed the RottenPotatoes DB with some movies. more_movies = [ {:title => 'Aladdin', :rating => 'G', :release_date => '25-Nov-1992'}, {:title => 'When Harry Met Sally', :rating => 'R', :release_date => '21-Jul-1989'}, {:title => 'The Help', :rating => 'PG-13', :release_date => '10-Aug-2011'}, {:title => 'Raiders of the Lost Ark', :rating => 'PG', :release_date => '12-Jun-1981'} ] Movie.send(:attr_accessible, :title, :rating, :release_date) more_movies.each do |movie| Movie.create!(movie) end

> rake db:seed

If the previous command fails, you should add the protected_attributes gem to your project.

Back at the rail console:

> Movie.all > Movie.where(‘id=2’) > Movie.find(4) > Movie.find_by_rating('PG') > Movie.where('release_date < :cutoff and rating = :rating', :cutoff => 'Jan 1 , 2000', :rating => 'G')

This allows us to interact with our application and DB and experiment with code without changing our web app implementation.

Get out of the console & let’s start building controllers and views for our actions.

> exit > rails server

If you reload your browser window (http://localhost:3000/movies), you should get an uninitialized constant for MoviesController . In another terminal window:

> gedit app/controllers/movies_controller.rb &

Paste the following (http://pastebin.com/KGWiEt09):

# This file is app/controllers/movies_controller.rb class MoviesController < ApplicationController def index @movies = Movie.all end end

> mkdir -p app/views/movies > gedit app/views/movies/index.html.haml &

And paste (http://pastebin.com/Bz9fuk34):

-# This file is app/views/movies/index.html.haml %h1 All Movies

%table#movies %thead %tr %th Movie Title %th Rating %th Release Date %th More Info %tbody - @movies.each do |movie| %tr %td= movie.title %td= movie.rating %td= movie.release_date %td= link_to "More about #{movie.title}", movie_path(movie)

Refresh your browser window (http://localhost:3000/movies), and you should see the same list of 4 movies that typing Movie.all gave you in the rails console (with prettier formatting).

Now let’s update the generic application wrapper (written in erb ) with one in haml :

> rm app/views/layouts/application.html.erb > gedit app/views/layouts/application.html.haml &

Paste (http://pastebin.com/0RU47cUy): !!! 5 %html %head %title Rotten Potatoes! = stylesheet_link_tag 'application' = javascript_include_tag 'application' = csrf_meta_tags

%body = yield

When you reload the page, you should see the page title change from MyRottenPotatoes -> Rotten Potatoes! Check out this screen cast to learn more about how these haml files are used to generate the html source code: http://vimeo.com/34754667

Let’s add the capability to show movie details.

In app/controllers/movies_controller.rb , add a show method (http://pastebin.com/TESrHmkk):

def show id = params[:id] # retrieve movie ID from URI route @movie = Movie.find(id) # look up movie by unique ID # will render app/views/movies/show.html.haml by default end

Now, add a haml view for action show .

> gedit app/views/movies/show.html.haml &

Paste:

%h2 Details about #{@movie.title}

%ul#details %li Rating: = @movie.rating %li Released on: = @movie.release_date.strftime("%B %d, %Y")

%h3 Description:

%p#description= @movie.description

= link_to 'Back to movie list', movies_path Click on a movie on the list, you should see some details. Now let’s make the movies view a little prettier by pasting a stylesheet (http://pastebin.com/LsLngdin) into:

> gedit app/assets/stylesheets/application. &

If you refresh the movie listings page, it should look more professional.

Now let’s allow users to add new movies through the web interface, rather than on the command line.

> gedit app/views/movies/index.html.haml &

And paste the following line to the end (http://pastebin.com/6wLiit6M):

= link_to 'Add new movie', new_movie_path

When you refresh the page, you should see a link to add a new movie at the bottom (but it won’t work yet).

> gedit app/views/movies/new.html.haml &

Paste (http://pastebin.com/eu3DFuMX):

%h2 Create New Movie

= form_tag movies_path, :method => :post do = label :movie, :title, 'Title' = text_field :movie, :title

= label :movie, :rating, 'Rating' = select :movie, :rating, Movie.all_ratings

= label :movie, :release_date, 'Released On' = date_select :movie, :release_date

= submit_tag 'Save Changes'

Add a new method inside the Movie class to app/controllers/movies_controller.rb :

def new # default: render ‘new’ template end

Now when you click on the link, you should see the “Create a new movie” page. Next we’ll enable the form to create a new movie in our app. > gedit app/controllers/movies_controller.rb &

Paste the following code inside the MovieController class (http://pastebin.com/FFgBP1Jy):

def create @movie = Movie.create!(params[:movie]) redirect_to movies_path end

Add the following line to your app/models/movie.rb file inside the Movie class:

attr_accessible :title, :rating, :description, :release_date

When you submit the form in the browser, it should now create a movie. Wouldn’t it be nice if the web page showed us a status update that our movie was or was not successfully added?

Update the create method in app/controllers/movies_controller.rb with the following flash message (http://pastebin.com/N1n4Pkr0):

# in movies_controller.rb def create @movie = Movie.create!(params[:movie]) flash[:notice] = "#{@movie.title} was successfully created." redirect_to movies_path end

Now we need to update the haml to get and display the message.

> gedit app/views/layouts/application.html.haml &

Paste the following if statement inside the body, before the yield command, like this:

%body - if flash[:notice] #notice.message= flash[:notice] - elsif flash[:warning] #warning.message= flash[:warning]

= yield

Remember that haml is VERY fussy about indentation and make sure you are consistent with tabs and spacing. Now when you add a movie, a status message should be displayed. Exercise: edit app/assets/stylesheets/application.css so that flash messages are red & centered.

Let’s add the ability to edit existing movies, which will require the following changes:

> gedit app/views/movies/show.html.haml &

Modify the last 2 lines to be (http://pastebin.com/ZD1y6TYc):

= link_to 'Edit info', edit_movie_path(@movie) = link_to 'Back to movie list', movies_path

> gedit app/views/movies/edit.html.haml &

Paste the properly indented haml code (http://pastebin.com/Uqm1AS8Q):

%h2 Edit Movie

= form_tag movie_path(@movie), :method => :put do

= label :movie, :title, 'Title' = text_field :movie, 'title'

= label :movie, :rating, 'Rating' = select :movie, :rating, Movie.all_ratings

= label :movie, :release_date, 'Released On' = date_select :movie, :release_date

= submit_tag 'Save Changes'

Add the following edit & update methods to app/controllers/movies_controller.rb (http://pastebin.com/jdTS5P7Q):

def edit @movie = Movie.find params[:id] end

def update @movie = Movie.find params[:id] @movie.update_attributes!(params[:movie]) flash[:notice] = "#{@movie.title} was successfully updated." redirect_to movie_path(@movie) end

Now you should have the ability to edit movies. But what if we want to delete one? Add the following lines to app/controllers/movies_controller.rb (http://pastebin.com/8ZYbFUcb):

def destroy @movie = Movie.find(params[:id]) @movie.destroy flash[:notice] = "Movie '#{@movie.title}' deleted." redirect_to movies_path end

And then add a delete link to app/views/movies/show.html.haml (http://pastebin.com/Cr8EXQaH):

-# Our Edit link from previous example: = link_to 'Edit info', edit_movie_path(@movie) -# This Delete link will not really be a link, but a form: = link_to 'Delete', movie_path(@movie), :method => :delete

You now should be able to delete a movie after clicking on a “more info” link. However, a destructive action like delete should probably prompt the user to be sure they want to take that action. So let’s change that delete link to a button instead (http://pastebin.com/mTXuE5up):

= button_to 'Delete', movie_path(@movie), :method => :delete, :confirm => 'Are you sure you want to delete?’

That concludes the chapter 4 walk through of a setting up a sample app from scratch. You should now have a better understanding of how the HW2 skeleton is setup.