Skip to content

Commit

Permalink
Add Recipe resource
Browse files Browse the repository at this point in the history
  • Loading branch information
Tray Torrance committed Feb 6, 2012
1 parent 866539d commit ed92036
Show file tree
Hide file tree
Showing 16 changed files with 481 additions and 2 deletions.
3 changes: 3 additions & 0 deletions app/assets/javascripts/recipes.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
3 changes: 3 additions & 0 deletions app/assets/stylesheets/recipes.css.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Place all the styles related to the recipes controller here.
// They will automatically be included in application.css.
// You can use Less here: http://lesscss.org/
87 changes: 87 additions & 0 deletions app/controllers/recipes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
class RecipesController < ApplicationController
# GET /recipes
# GET /recipes.json
def index
@recipes = Recipe.all

respond_to do |format|
format.html
format.xml { render_for_api :public, :xml => @recipes, :location => :recipes }
format.json { render_for_api :public, :json => @recipes, :location => :recipes }
end
end

# GET /recipes/1
# GET /recipes/1.json
def show
@recipe = Recipe.find(params[:id])

respond_to do |format|
format.html
format.xml { render_for_api :public, :xml => @recipe }
format.json { render_for_api :public, :json => @recipe }
end
end

# GET /recipes/new
# GET /recipes/new.json
def new
@recipe = Recipe.new

respond_to do |format|
format.html
format.xml { render_for_api :public, :xml => @recipe }
format.json { render_for_api :public, :json => @recipe }
end
end

# GET /recipes/1/edit
def edit
@recipe = Recipe.find(params[:id])
end

# POST /recipes
# POST /recipes.json
def create
@recipe = Recipe.new(params[:recipe])

respond_to do |format|
if @recipe.save
format.html { redirect_to @recipe, :notice => 'Recipe was successfully created.' }
format.xml { render_for_api :public, :xml => @recipe, :status => :created, :location => @recipe }
format.json { render_for_api :public, :json => @recipe, :status => :created, :location => @recipe }
else
format.html { render :action => "new" }
format.json { render :json => @recipe.errors, :status => :unprocessable_entity }
end
end
end

# PUT /recipes/1
# PUT /recipes/1.json
def update
@recipe = Recipe.find(params[:id])

respond_to do |format|
if @recipe.update_attributes(params[:recipe])
format.html { redirect_to @recipe, :notice => 'Recipe was successfully updated.' }
format.json { head :ok }
else
format.html { render :action => "edit" }
format.json { render :json => @recipe.errors, :status => :unprocessable_entity }
end
end
end

# DELETE /recipes/1
# DELETE /recipes/1.json
def destroy
@recipe = Recipe.find(params[:id])
@recipe.destroy

respond_to do |format|
format.html { redirect_to recipes_url }
format.json { head :ok }
end
end
end
36 changes: 36 additions & 0 deletions app/models/recipe.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class Recipe
include Mongoid::Document

# Define and validate a recipe name
field :name, :type => String
validates_presence_of :name, :message => 'Name cannot be blank'
validates_uniqueness_of :name, :case_sensitive => false

# Define description and direction fields
field :description, :type => String, :default => ''
field :directions, :type => String, :default => ''

# A Recipe embeds several RecipeIngredients
embeds_many :recipe_ingredients

# Determine if a Recipe is vegetarian based on
# whether or not its ingredients are all vegetarian
def vegetarian?
# Collect an array of the vegetarian state of each ingredient
# and check it for any 'false' entries
self.recipe_ingredients.collect do |ingredient|
ingredient.vegetarian?
end.include?( false ) == false
end

# Expose Recipes to the API
acts_as_api
api_accessible :public do |template|
template.add :name
template.add :description
template.add :directions
template.add :recipe_ingredients, :as => :ingredients
template.add 'vegetarian?'.to_sym, :as => :is_veg
end
end

5 changes: 5 additions & 0 deletions app/views/recipes/_form.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
= simple_form_for @recipe, :validate => true, :html => { :class => 'form-horizontal' } do |f|
= f.input :name
= f.input :description, :as => :text, :input_html => { :rows => 5 }
= f.input :directions, :as => :text, :input_html => { :rows => 5 }
= f.button :submit
7 changes: 7 additions & 0 deletions app/views/recipes/edit.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
%h1 Edit Recipe

= render 'form'

= link_to 'Show', @recipe
\|
= link_to 'Back', recipes_path
22 changes: 22 additions & 0 deletions app/views/recipes/index.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
%h1 Recipe Listing

%table{ :class => 'table-condensed table-striped' }
%thead
%tr
%th Name
%th Description
%th Directions
%th
%th

- @recipes.each do |recipe|
%tr
%td= link_to recipe.name, recipe
%td= recipe.description
%td= recipe.directions
%td= link_to 'Edit', edit_recipe_path(recipe)
%td= link_to 'Destroy', recipe, :confirm => 'Are you sure?', :method => :delete

%br

= link_to 'New Recipe', new_recipe_path
5 changes: 5 additions & 0 deletions app/views/recipes/new.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
%h1 New Recipe

= render 'form'

= link_to 'Back', recipes_path
22 changes: 22 additions & 0 deletions app/views/recipes/show.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
%h1 Recipe Details

%p#notice= notice

%p
%b Name:
= @recipe.name
%p
%b Description:
= @recipe.description
%p
%b Ingredients:
%ul
- @recipe.recipe_ingredients.each do |ingredient|
%p.ingredient= "#{pluralize ingredient.quantity, ingredient.unit} #{ingredient.name}"
%p
%b Directions:
= @recipe.directions

= link_to 'Edit', edit_recipe_path(@recipe)
\|
= link_to 'Back', recipes_path
4 changes: 2 additions & 2 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CookingWithRails::Application.routes.draw do
resources :ingredients
root :to => 'ingredients#index'
resources :ingredients, :recipes
root :to => 'recipes#index'

# The priority is based upon order of creation:
# first created -> highest priority.
Expand Down
166 changes: 166 additions & 0 deletions spec/controllers/recipes_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
require 'spec_helper'

# This spec was generated by rspec-rails when you ran the scaffold generator.
# It demonstrates how one might use RSpec to specify the controller code that
# was generated by Rails when you ran the scaffold generator.
#
# It assumes that the implementation code is generated by the rails scaffold
# generator. If you are using any extension libraries to generate different
# controller code, this generated spec may or may not pass.
#
# It only uses APIs available in rails and/or rspec-rails. There are a number
# of tools you can use to make these specs even more expressive, but we're
# sticking to rails and rspec-rails APIs to keep things simple and stable.
#
# Compared to earlier versions of this generator, there is very limited use of
# stubs and message expectations in this spec. Stubs are only used when there
# is no simpler way to get a handle on the object needed for the example.
# Message expectations are only used when there is no simpler way to specify
# that an instance is receiving a specific message.

describe RecipesController do

# This should return the minimal set of attributes required to create a valid
# Recipe. As you add validations to Recipe, be sure to
# update the return value of this method accordingly.
def valid_attributes
{
:name => 'RecipeName',
}
end

# This should return the minimal set of values that should be in the session
# in order to pass any filters (e.g. authentication) defined in
# RecipesController. Be sure to keep this updated too.
def valid_session
{}
end

describe "GET index" do
it "assigns all recipes as @recipes" do
recipe = Recipe.create! valid_attributes
get :index, {}, valid_session
assigns(:recipes).should eq([recipe])
end
end

describe "GET show" do
it "assigns the requested recipe as @recipe" do
recipe = Recipe.create! valid_attributes
get :show, {:id => recipe.to_param}, valid_session
assigns(:recipe).should eq(recipe)
end
end

describe "GET new" do
it "assigns a new recipe as @recipe" do
get :new, {}, valid_session
assigns(:recipe).should be_a_new(Recipe)
end
end

describe "GET edit" do
it "assigns the requested recipe as @recipe" do
recipe = Recipe.create! valid_attributes
get :edit, {:id => recipe.to_param}, valid_session
assigns(:recipe).should eq(recipe)
end
end

describe "POST create" do
describe "with valid params" do
it "creates a new Recipe" do
expect {
post :create, {:recipe => valid_attributes}, valid_session
}.to change(Recipe, :count).by(1)
end

it "assigns a newly created recipe as @recipe" do
post :create, {:recipe => valid_attributes}, valid_session
assigns(:recipe).should be_a(Recipe)
assigns(:recipe).should be_persisted
end

it "redirects to the created recipe" do
post :create, {:recipe => valid_attributes}, valid_session
response.should redirect_to(Recipe.last)
end
end

describe "with invalid params" do
it "assigns a newly created but unsaved recipe as @recipe" do
# Trigger the behavior that occurs when invalid params are submitted
Recipe.any_instance.stub(:save).and_return(false)
post :create, {:recipe => {}}, valid_session
assigns(:recipe).should be_a_new(Recipe)
end

it "re-renders the 'new' template" do
# Trigger the behavior that occurs when invalid params are submitted
Recipe.any_instance.stub(:save).and_return(false)
post :create, {:recipe => {}}, valid_session
response.should render_template("new")
end
end
end

describe "PUT update" do
describe "with valid params" do
it "updates the requested recipe" do
recipe = Recipe.create! valid_attributes
# Assuming there are no other recipes in the database, this
# specifies that the Recipe created on the previous line
# receives the :update_attributes message with whatever params are
# submitted in the request.
Recipe.any_instance.should_receive(:update_attributes).with({'these' => 'params'})
put :update, {:id => recipe.to_param, :recipe => {'these' => 'params'}}, valid_session
end

it "assigns the requested recipe as @recipe" do
recipe = Recipe.create! valid_attributes
put :update, {:id => recipe.to_param, :recipe => valid_attributes}, valid_session
assigns(:recipe).should eq(recipe)
end

it "redirects to the recipe" do
recipe = Recipe.create! valid_attributes
put :update, {:id => recipe.to_param, :recipe => valid_attributes}, valid_session
response.should redirect_to(recipe)
end
end

describe "with invalid params" do
it "assigns the recipe as @recipe" do
recipe = Recipe.create! valid_attributes
# Trigger the behavior that occurs when invalid params are submitted
Recipe.any_instance.stub(:save).and_return(false)
put :update, {:id => recipe.to_param, :recipe => {}}, valid_session
assigns(:recipe).should eq(recipe)
end

it "re-renders the 'edit' template" do
recipe = Recipe.create! valid_attributes
# Trigger the behavior that occurs when invalid params are submitted
Recipe.any_instance.stub(:save).and_return(false)
put :update, {:id => recipe.to_param, :recipe => {}}, valid_session
response.should render_template("edit")
end
end
end

describe "DELETE destroy" do
it "destroys the requested recipe" do
recipe = Recipe.create! valid_attributes
expect {
delete :destroy, {:id => recipe.to_param}, valid_session
}.to change(Recipe, :count).by(-1)
end

it "redirects to the recipes list" do
recipe = Recipe.create! valid_attributes
delete :destroy, {:id => recipe.to_param}, valid_session
response.should redirect_to(recipes_url)
end
end

end
Loading

0 comments on commit ed92036

Please sign in to comment.