Home

kristianmandrup edited this page Sep 14, 2010 · 10 revisions
Clone this wiki locally

Cucumber BDD Recipe for Movie App

Ensure these gems are installed on your system


$ gem list
cucumber-rails-0.8.0
rspec-rails-2.0.0.beta11

These gems must be installed as system gems for fx autotest to work.

$ cucumber -t @focus

Create Movie model

$ rails g model movie showtime_date:date showtime_time:time
$ rake db:migrate && rake db:test:prepare 
class Movie < ActiveRecord::Base
  def showtime 
    "#{formatted_date} (#{formatted_time})"
  end

  def formatted_date 
    showtime_date.strftime("%B %d, %Y")
  end

  def formatted_time 
    format_string = showtime_time.min.zero? ? "%l%p" : "%l:%M%p" 
    showtime_time.strftime(format_string).strip.downcase
  end
end

Create Genre model

$ rails g model genre name:string
$ rake db:migrate && rake db:test:prepare

Create Movies controller

$ rails g controller Movies index new

movies_controller.rb


class MoviesController < ApplicationController
  def index
  end
def new
@movie = Movie.new
@genres = Genre.all
end
def create
redirect_to movies_path
end

end

Create Movies views

<%= link_to "Add Movie", new_movie_path %>

movies/new.html.erb

<%= form_for @movie do |f| %>
  <label>
    Title
    <%= f.text_field :title %>


Release Year
<%= f.select :release_year, (1900..2009).to_a.map(&:to_s) %>

<% @genres.each do |genre| %>

<%=h genre.name %>
<%= check_box_tag “genres[]”, genre.id %>

<% end %>
<%= f.submit “Save”   %>

<% end %>

Add movies REST resources to routes

routes.rb


  resources :movies

Add more attributes to movies

$ rails g migration add_title_to_movies title:string
$ rails g migration add_release_year_to_movies release_year:date
$ rake db:migrate && rake db:test:prepare

Create GenresMovies join table

$ rails g migration create_genres_movies

class CreateGenresMovies < ActiveRecord::Migration
  def self.up
    create_table :genres_movies, :id => false, :force => true do |t|
      t.integer :genre_id
      t.integer :movie_id
      t.timestamps
    end
  end

  def self.down
    drop_table :genres_movies
  end
end

Create Genres controller

$ rails g controller Genres index show

class GenresController < ApplicationController  
  def index
    @genres = Genre.all
  end

  def show
    @genre = Genre.find(params[:id])
  end  
end

Add genres REST resources to routes

routes.rb


  resources :products, :movies, :genres 

Create Genre views

genres/index.html.erb

<% @genres.each do |genre| %>
  <%= link_to genre.name, genre %>
<% end %>

genres/show.html.erb

<%=h @genre.name %>
<%= @genre.movies.count %> movie
<% @genre.movies.each do |movie| %>
  <%= link_to movie.title, movie %>
<% end %>

Implement create movies controller action

movies_controller.rb

def create
  movie = Movie.create!(params[:movie]) # create movie
  genres = Genre.find(params[:genres]) # find genres
  movie.genres = genres # add genres to movie
  movie.save! # save movie
  redirect_to movies_path # go to movie index page
end

Add Movies to Genre model

models/genre.rb

class Genre < ActiveRecord::Base
  has_and_belongs_to_many :movies
end

Add Genres to Movie model

models/movie.rb

class Movie < ActiveRecord::Base
  has_and_belongs_to_many :genres

  1. end

Create ‘Comedy’ Genre in Database

$ RAILS_ENV=test rails c
> Genre.create(name:"Comedy")
 => #<Genre id: 1, name: "Comedy", created_at: "2010-06-09 09:31:49", updated_at: "2010-06-09 09:31:49"> 
> exit

Change DSL to Capybara syntax

movie_steps.rb

Then /^Caddyshack should be in the Comedy genre$/ do
  visit genres_path 
  click_link "Comedy" 
  page.should have_content("1 movie")     # Capybara DSL
  page.should have_content("Caddyshack")  
end