diff --git a/.gitignore b/.gitignore index 354eb8e0..dba9801e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ !/log/.keep /tmp coverage/ +/public/uploads diff --git a/Gemfile b/Gemfile index d142e2fa..7bf46eb4 100644 --- a/Gemfile +++ b/Gemfile @@ -27,6 +27,10 @@ gem 'sdoc', '~> 0.4.0', group: :doc gem 'bcrypt', '~> 3.1.7' gem 'bootstrap-sass' +# for uploads +gem 'mini_magick' +gem 'carrierwave' + # Use Unicorn as the app server # gem 'unicorn' diff --git a/Gemfile.lock b/Gemfile.lock index 057a4eb0..55045193 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -53,6 +53,11 @@ GEM builder (3.2.2) byebug (5.0.0) columnize (= 0.9.0) + carrierwave (0.10.0) + activemodel (>= 3.2.0) + activesupport (>= 3.2.0) + json (>= 1.7) + mime-types (>= 1.16) coderay (1.1.0) coffee-rails (4.1.0) coffee-script (>= 2.2.0) @@ -89,6 +94,7 @@ GEM mime-types (>= 1.16, < 3) method_source (0.8.2) mime-types (2.6.1) + mini_magick (4.2.7) mini_portile (0.6.2) minitest (5.7.0) multi_json (1.11.2) @@ -196,10 +202,12 @@ DEPENDENCIES binding_of_caller bootstrap-sass byebug + carrierwave coffee-rails (~> 4.1.0) factory_girl_rails (~> 4.0) jbuilder (~> 2.0) jquery-rails + mini_magick pg pry-rails rails (= 4.2.3) diff --git a/app/assets/.DS_Store b/app/assets/.DS_Store new file mode 100644 index 00000000..0de5ed1f Binary files /dev/null and b/app/assets/.DS_Store differ diff --git a/app/assets/images/almond_butter.jpg b/app/assets/images/almond_butter.jpg new file mode 100644 index 00000000..bf4d2a93 Binary files /dev/null and b/app/assets/images/almond_butter.jpg differ diff --git a/app/assets/images/almonds.jpg b/app/assets/images/almonds.jpg new file mode 100644 index 00000000..543a7700 Binary files /dev/null and b/app/assets/images/almonds.jpg differ diff --git a/app/assets/images/black_pepper.jpg b/app/assets/images/black_pepper.jpg new file mode 100644 index 00000000..8b296bfe Binary files /dev/null and b/app/assets/images/black_pepper.jpg differ diff --git a/app/assets/images/bok_choy.jpg b/app/assets/images/bok_choy.jpg new file mode 100644 index 00000000..30c24241 Binary files /dev/null and b/app/assets/images/bok_choy.jpg differ diff --git a/app/assets/images/bokchoy_pineapple.jpg b/app/assets/images/bokchoy_pineapple.jpg new file mode 100644 index 00000000..be10af7c Binary files /dev/null and b/app/assets/images/bokchoy_pineapple.jpg differ diff --git a/app/assets/images/chicken.jpg b/app/assets/images/chicken.jpg new file mode 100644 index 00000000..69fcc4c1 Binary files /dev/null and b/app/assets/images/chicken.jpg differ diff --git a/app/assets/images/choc_ice_cream.jpg b/app/assets/images/choc_ice_cream.jpg new file mode 100644 index 00000000..de0a21f8 Binary files /dev/null and b/app/assets/images/choc_ice_cream.jpg differ diff --git a/app/assets/images/cilantro.jpg b/app/assets/images/cilantro.jpg new file mode 100644 index 00000000..f064456c Binary files /dev/null and b/app/assets/images/cilantro.jpg differ diff --git a/app/assets/images/cocoa-powder.jpg b/app/assets/images/cocoa-powder.jpg new file mode 100644 index 00000000..85ac071e Binary files /dev/null and b/app/assets/images/cocoa-powder.jpg differ diff --git a/app/assets/images/coconut_milk.jpg b/app/assets/images/coconut_milk.jpg new file mode 100644 index 00000000..84cd5388 Binary files /dev/null and b/app/assets/images/coconut_milk.jpg differ diff --git a/app/assets/images/coconut_oil.jpg b/app/assets/images/coconut_oil.jpg new file mode 100644 index 00000000..e47d1059 Binary files /dev/null and b/app/assets/images/coconut_oil.jpg differ diff --git a/app/assets/images/default_256.png b/app/assets/images/default_256.png new file mode 100644 index 00000000..9e0e354e Binary files /dev/null and b/app/assets/images/default_256.png differ diff --git a/app/assets/images/fake_reeses.jpg b/app/assets/images/fake_reeses.jpg new file mode 100644 index 00000000..6516ceed Binary files /dev/null and b/app/assets/images/fake_reeses.jpg differ diff --git a/app/assets/images/honey.jg.jpg b/app/assets/images/honey.jg.jpg new file mode 100644 index 00000000..0c394397 Binary files /dev/null and b/app/assets/images/honey.jg.jpg differ diff --git a/app/assets/images/honey.jpg b/app/assets/images/honey.jpg new file mode 100644 index 00000000..0c394397 Binary files /dev/null and b/app/assets/images/honey.jpg differ diff --git a/app/assets/images/maple_syrup.jpg b/app/assets/images/maple_syrup.jpg new file mode 100644 index 00000000..9ba5dba1 Binary files /dev/null and b/app/assets/images/maple_syrup.jpg differ diff --git a/app/assets/images/olive_oil.jpg b/app/assets/images/olive_oil.jpg new file mode 100644 index 00000000..61ead9e1 Binary files /dev/null and b/app/assets/images/olive_oil.jpg differ diff --git a/app/assets/images/pineapple.jpg b/app/assets/images/pineapple.jpg new file mode 100644 index 00000000..172f5054 Binary files /dev/null and b/app/assets/images/pineapple.jpg differ diff --git a/app/assets/images/sea_salt.jpg b/app/assets/images/sea_salt.jpg new file mode 100644 index 00000000..86faa962 Binary files /dev/null and b/app/assets/images/sea_salt.jpg differ diff --git a/app/assets/images/yam.jpg b/app/assets/images/yam.jpg new file mode 100644 index 00000000..4ee014da Binary files /dev/null and b/app/assets/images/yam.jpg differ diff --git a/app/assets/images/yam_chips.jpg b/app/assets/images/yam_chips.jpg new file mode 100644 index 00000000..1a489b2b Binary files /dev/null and b/app/assets/images/yam_chips.jpg differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e07c5a83..74658567 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -13,4 +13,5 @@ //= require jquery //= require jquery_ujs //= require turbolinks +//= require bootstrap-sprockets //= require_tree . diff --git a/app/assets/javascripts/cookbooks.coffee b/app/assets/javascripts/cookbooks.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/cookbooks.coffee @@ -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://coffeescript.org/ diff --git a/app/assets/javascripts/home.coffee b/app/assets/javascripts/home.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/home.coffee @@ -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://coffeescript.org/ diff --git a/app/assets/javascripts/ingredients.coffee b/app/assets/javascripts/ingredients.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/ingredients.coffee @@ -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://coffeescript.org/ diff --git a/app/assets/javascripts/recipes.coffee b/app/assets/javascripts/recipes.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/recipes.coffee @@ -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://coffeescript.org/ diff --git a/app/assets/javascripts/sessions.coffee b/app/assets/javascripts/sessions.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/sessions.coffee @@ -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://coffeescript.org/ diff --git a/app/assets/javascripts/users.coffee b/app/assets/javascripts/users.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/users.coffee @@ -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://coffeescript.org/ diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.scss similarity index 80% rename from app/assets/stylesheets/application.css rename to app/assets/stylesheets/application.scss index f9cd5b34..8569d5ba 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.scss @@ -1,3 +1,4 @@ + /* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. @@ -13,3 +14,16 @@ *= require_tree . *= require_self */ + + @import "bootstrap-sprockets"; + @import "bootstrap"; + + $error: #F72B1D; /* red for warining */ + + .container { + margin-top: 30px + } + + .error { + color: $error; +} diff --git a/app/assets/stylesheets/cookbooks.scss b/app/assets/stylesheets/cookbooks.scss new file mode 100644 index 00000000..7ccd3d3f --- /dev/null +++ b/app/assets/stylesheets/cookbooks.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Cookbooks controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/home.scss b/app/assets/stylesheets/home.scss new file mode 100644 index 00000000..f0ddc684 --- /dev/null +++ b/app/assets/stylesheets/home.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the home controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/ingredients.scss b/app/assets/stylesheets/ingredients.scss new file mode 100644 index 00000000..98f8d500 --- /dev/null +++ b/app/assets/stylesheets/ingredients.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the ingredients controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/recipes.scss b/app/assets/stylesheets/recipes.scss new file mode 100644 index 00000000..1e10ffa5 --- /dev/null +++ b/app/assets/stylesheets/recipes.scss @@ -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 Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/sessions.scss b/app/assets/stylesheets/sessions.scss new file mode 100644 index 00000000..7bef9cf8 --- /dev/null +++ b/app/assets/stylesheets/sessions.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the sessions controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/users.scss b/app/assets/stylesheets/users.scss new file mode 100644 index 00000000..1efc835c --- /dev/null +++ b/app/assets/stylesheets/users.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the users controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d83690e1..42af2e26 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,4 +2,13 @@ class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception + MESSAGES = {not_logged_in: "You must be logged in to view this page!" } + + def require_login + redirect_to login_path, flash: {error: MESSAGES[:not_logged_in]} unless session[:user_id] + end + + # def user_cookbooks + # redirect_to root_path unless session[:user_id] + # end end diff --git a/app/controllers/cookbooks_controller.rb b/app/controllers/cookbooks_controller.rb new file mode 100644 index 00000000..66fa3ef7 --- /dev/null +++ b/app/controllers/cookbooks_controller.rb @@ -0,0 +1,54 @@ +class CookbooksController < ApplicationController + before_action :require_login, only: [:show, :edit] + before_action :find_cookbook, only: [:show, :edit, :update, :destroy] + + def new + @cookbook = Cookbook.new + end + + def create + @cookbook = Cookbook.create(cookbook_params) + @cookbook.user_id = session[:user_id] + + if @cookbook.save + redirect_to user_path(session[:user_id]) + else + flash[:name] = "Please provide a name for your cookbook." + render 'new' + end + end + + def show + session[:cookbook_id] = @cookbook.id + if session[:user_id] != @cookbook.user_id + redirect_to user_path(session[:user_id]) + end + + end + + def edit + @cookbook = Cookbook.find(params[:id]) + if session[:user_id] != @cookbook.user_id + redirect_to user_path(session[:user_id]) + end + end + + def update + @cookbook.update(cookbook_params) + redirect_to user_path(session[:user_id]) + end + + def destroy + @cookbook.destroy + redirect_to user_path(session[:user_id]) + end + + private + def find_cookbook + @cookbook = Cookbook.find(params[:id]) + end + + def cookbook_params + params.require(:cookbook).permit(:name, :description, {:recipe_ids => [] }) + end +end diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb new file mode 100644 index 00000000..72718156 --- /dev/null +++ b/app/controllers/home_controller.rb @@ -0,0 +1,5 @@ +class HomeController < ApplicationController + def index + @recipes = Recipe.all + end +end diff --git a/app/controllers/ingredients_controller.rb b/app/controllers/ingredients_controller.rb new file mode 100644 index 00000000..c093b131 --- /dev/null +++ b/app/controllers/ingredients_controller.rb @@ -0,0 +1,63 @@ +class IngredientsController < ApplicationController + before_action :find_ingredient, only: [:show, :destroy] + before_action :require_login, only: [:new] + + def index + @ingredients = Ingredient.all.alphabet + end + + def edit + @ingredient = Ingredient.find(params[:id]) + if session[:user_id] != @ingredient.user_id + redirect_to ingredient_path(@ingredient) + end + end + + def update + @ingredient = Ingredient.find(params[:id]) + @ingredient.update(ingredient_params) + + if @ingredient.save + redirect_to user_path(session[:user_id]) + else + flash[:name] = "Please provide your ingredient name." + render :edit + end + end + + def show + @ingredient = find_ingredient + end + + def new + @ingredient = Ingredient.new + end + + def create + @ingredient = Ingredient.new(ingredient_params) + @ingredient.user_id = session[:user_id] + if @ingredient.save + redirect_to ingredient_path(@ingredient) + else + flash[:name] = "Please provide your ingredient name." + render :new + end + end + + def destroy + @ingredient.destroy + + redirect_to user_path(session[:user_id]) + end + + private + + def find_ingredient + @ingredient = Ingredient.find(params[:id]) + end + + def ingredient_params + params.require(:ingredient).permit(:name, :image) + end + +end diff --git a/app/controllers/recipes_controller.rb b/app/controllers/recipes_controller.rb new file mode 100644 index 00000000..1f35da7e --- /dev/null +++ b/app/controllers/recipes_controller.rb @@ -0,0 +1,96 @@ +class RecipesController < ApplicationController + before_action :require_login, only: [:new, :add] + + def index + if params[:search] + @recipes = Recipe.search(params[:search]) + render :results + else + @recipes = Recipe.all.alphabet + render :index + end + end + + def edit + @recipe = Recipe.find(params[:id]) + if session[:user_id] != @recipe.user_id + redirect_to recipe_path(@recipe) + end + end + + def update + @recipe = Recipe.find(params[:id]) + @recipe.update(recipe_params) + + if @recipe.save + redirect_to user_path(session[:user_id]) + else + render :edit + end + + end + + def new + @user = User.find(session[:user_id]) + @recipe = Recipe.new(user_id: @user.id) + @ingredients = Ingredient.all + @cookbook = Cookbook.where(user_id: @user.id ) + end + + def show + @recipe = Recipe.find(params[:id]) + # @user = User.find(@recipe.user_id).username.capitalize + @user_recipes = User.find(@recipe.user_id).username.capitalize + @your_cookbook = User.find(session[:user_id]).cookbooks if session[:user_id] + end + + def add + @user = User.find(session[:user_id]) + @recipe = Recipe.find(params[:id]) + @cookbook = Cookbook.where(user_id: @user.id) + render :add + end + + def create + @recipe = Recipe.new(recipe_params) + @recipe.user_id = session[:user_id] + @recipe.validate + + if @recipe.valid? + @ingredient_recipe = (params[:recipe][:ingredient_ids].first).to_i + @recipe.ingredients << Ingredient.find(@ingredient_recipe) unless @ingredient_recipe != 0 + # This prevents anything from being saved if the user didn't input any ingredients for a recipe + @recipe.save + redirect_to user_path(session[:user_id]) + else + @cookbook = Cookbook.where(user_id: session[:user_id]) + @user = User.find(session[:user_id]) + @ingredients = Ingredient.all + @recipe = Recipe.new(user_id: @user.id) + render :new + end + end + + def remove_recipe + cookbook = Cookbook.find(session[:cookbook_id]) + recipe = Recipe.find(params[:recipe_id]) + + if cookbook + recipe.cookbooks.delete(cookbook) + redirect_to root_path + end + end + + def destroy + @recipe = Recipe.find(params[:id]) + @recipe.destroy + redirect_to user_path(session[:user_id]) + end + + private + + + def recipe_params + params.require(:recipe).permit(:user_id, :recipe_id, :name, :description, :image, :ingredients, :preparation, {:ingredient_ids => [] }, {:cookbook_ids => [] }) + end +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 00000000..7efafe70 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,22 @@ +class SessionsController < ApplicationController + def new + end + + def create + @user = User.find_by_username(params[:session][:username]) + + if @user && @user.authenticate(params[:session][:password]) + session[:user_id] = @user.id + redirect_to user_path(session[:user_id]) + else + flash.now[:error] = "Incorrect Username/Password Combination, Please Try Again." + render 'new' + end + end + + def destroy + session[:user_id] = nil + redirect_to login_path + end + +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 00000000..75e25850 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,36 @@ +class UsersController < ApplicationController + before_action :require_login, only: [:show] + + def new + @user = User.new + end + + def create + @user = User.new(user_params) + @user.save + + if @user.save + redirect_to login_url + else + redirect_to signup_path + end + + end + + def show + @user = User.find(session[:user_id]) + @cookbooks = Cookbook.where(user_id: @user.id ) + @recipes = Recipe.where(user_id: @user.id ) + @ingredients = Ingredient.where(user_id: @user.id) + end + + def view + @user = User.find(params[:id]) + end + +private + + def user_params + params.require(:user).permit(:username, :password, :password_confirmation) + end +end diff --git a/app/helpers/cookbooks_helper.rb b/app/helpers/cookbooks_helper.rb new file mode 100644 index 00000000..d48e47c5 --- /dev/null +++ b/app/helpers/cookbooks_helper.rb @@ -0,0 +1,2 @@ +module CookbooksHelper +end diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb new file mode 100644 index 00000000..23de56ac --- /dev/null +++ b/app/helpers/home_helper.rb @@ -0,0 +1,2 @@ +module HomeHelper +end diff --git a/app/helpers/ingredients_helper.rb b/app/helpers/ingredients_helper.rb new file mode 100644 index 00000000..dd54783a --- /dev/null +++ b/app/helpers/ingredients_helper.rb @@ -0,0 +1,2 @@ +module IngredientsHelper +end diff --git a/app/helpers/recipes_helper.rb b/app/helpers/recipes_helper.rb new file mode 100644 index 00000000..f526316e --- /dev/null +++ b/app/helpers/recipes_helper.rb @@ -0,0 +1,2 @@ +module RecipesHelper +end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb new file mode 100644 index 00000000..309f8b2e --- /dev/null +++ b/app/helpers/sessions_helper.rb @@ -0,0 +1,2 @@ +module SessionsHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 00000000..2310a240 --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/app/models/cookbook.rb b/app/models/cookbook.rb new file mode 100644 index 00000000..a8845fbd --- /dev/null +++ b/app/models/cookbook.rb @@ -0,0 +1,10 @@ +class Cookbook < ActiveRecord::Base + # Associations ---------------------------------- + belongs_to :user + has_and_belongs_to_many :recipes + + # Validations ------------------------------------ + validates :name, presence: true + # Scope_____________________________________________ + +end diff --git a/app/models/ingredient.rb b/app/models/ingredient.rb new file mode 100644 index 00000000..41b50980 --- /dev/null +++ b/app/models/ingredient.rb @@ -0,0 +1,14 @@ +class Ingredient < ActiveRecord::Base + # uploader ------ + mount_uploader :image, ImageUploader + # Associations ---------------------------------- + has_and_belongs_to_many :recipes + belongs_to :user + + # Validations ------------------------------------ + validates :name, presence: true, uniqueness: true + + # Scopes ----------------------------------------- + scope :alphabet, -> { order('lower (name)') } + +end diff --git a/app/models/recipe.rb b/app/models/recipe.rb new file mode 100644 index 00000000..4d91d274 --- /dev/null +++ b/app/models/recipe.rb @@ -0,0 +1,26 @@ +class Recipe < ActiveRecord::Base + # uploader ------ + mount_uploader :image, ImageUploader + # Associations ---------------------------------- + has_and_belongs_to_many :ingredients + has_and_belongs_to_many :cookbooks + belongs_to :user + + # Validations ---------------------------------------------------------------- + validates :name, presence: true + validates :preparation, presence: true + validates_with RecipeValidator, :on => [:create, :update] + + # Scopes ----------------------------------------- + scope :alphabet, -> { order('lower (name)') } + scope :diff, -> { select(:ingredients).distinct.order(:ingredients).pluck(:ingredients) } + + # Mounted Objects_____________________________________________________________ + # mount_uploader :image, ImageUploader #instance of class image uploader + + def self.search(query) + where("name like ?", "%#{query}%" ) + end + + +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 00000000..ad3fcccd --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,12 @@ +class User < ActiveRecord::Base + # Associations ---------------------------------- + has_many :cookbooks + has_many :recipes + has_many :ingredients + + has_secure_password + + validates :username, presence: true + + +end diff --git a/app/uploaders/image_uploader.rb b/app/uploaders/image_uploader.rb new file mode 100644 index 00000000..13cbd0e4 --- /dev/null +++ b/app/uploaders/image_uploader.rb @@ -0,0 +1,55 @@ +# encoding: utf-8 + +class ImageUploader < CarrierWave::Uploader::Base + + # Include RMagick or MiniMagick support: + # include CarrierWave::RMagick + include CarrierWave::MiniMagick + + # Choose what kind of storage to use for this uploader: + storage :file + # storage :fog + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + def default_url + # For Rails 3.1+ asset pipeline compatibility: + # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_')) + "default_256.png" + # "/images/fallback/" + [version_name, "default.png"].compact.join('_') + end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + version :thumb do + process :resize_to_fit => [75, 75] + end + + version :medium do + process :resize_to_fit => [500, 500] + end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + def extension_white_list + %w(jpg jpeg gif png) + end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + +end diff --git a/app/validators/recipe_validator.rb b/app/validators/recipe_validator.rb new file mode 100644 index 00000000..0a09948a --- /dev/null +++ b/app/validators/recipe_validator.rb @@ -0,0 +1,10 @@ +class RecipeValidator < ActiveModel::Validator + def validate(recipe) + # Do nothing for now. + # We must create an order before we create an order_item, + # so the initial order must temporarily not have any order items + unless recipe.ingredients.length >= 1 + recipe.errors.add(:ingredient, "recipe must have at least 1 ingredient") + end + end +end diff --git a/app/views/cookbooks/_form.html.erb b/app/views/cookbooks/_form.html.erb new file mode 100644 index 00000000..c9af0a02 --- /dev/null +++ b/app/views/cookbooks/_form.html.erb @@ -0,0 +1,26 @@ +<%= form_for @cookbook do |f| %> +
+ <% flash.each do|name, message| %> +
<%= message %>
+ <% end %> + +
+ <%= f.label :name, "Cookbook Name" %> + <%= f.text_field :name, class: "form-control" %> + + <%= f.label :description, "Cookbook Description" %> + <%= f.text_area :description, class: "form-control" %> + +
+ + <%= f.label :recipes, :required => true %>
+ <%= collection_check_boxes(:cookbook, :recipe_ids, Recipe.all, :id, :name) do |b| %> + <%= b.label class: "checkbox" do %> + <%= b.check_box + b.text.capitalize %> + <% end %> + <% end %> + +
+ <%= f.submit "Submit", class: "btn btn-default"%> +
+ <% end %> diff --git a/app/views/cookbooks/edit.html.erb b/app/views/cookbooks/edit.html.erb new file mode 100644 index 00000000..1a92c44d --- /dev/null +++ b/app/views/cookbooks/edit.html.erb @@ -0,0 +1,5 @@ +

Edit <%= @cookbook.name %>!

+ +
+ <%= render partial: "form" %> +
diff --git a/app/views/cookbooks/new.html.erb b/app/views/cookbooks/new.html.erb new file mode 100644 index 00000000..1a42c8c1 --- /dev/null +++ b/app/views/cookbooks/new.html.erb @@ -0,0 +1,5 @@ +

Add a Cookbook!

+ +
+ <%= render partial: "form" %> +
diff --git a/app/views/cookbooks/show.html.erb b/app/views/cookbooks/show.html.erb new file mode 100644 index 00000000..873fac27 --- /dev/null +++ b/app/views/cookbooks/show.html.erb @@ -0,0 +1,15 @@ +
+

<%= @cookbook.name %>

<%= link_to "Edit Cookbook", edit_cookbook_path(@cookbook.id), class:"btn btn-primary" %> +

Description: <%= @cookbook.description %>

+ +

Recipes

+
+ <% @cookbook.recipes.alphabet.each do |recipe| %> +
+

<%= link_to "#{recipe.name}", recipe_path(recipe.id) %>

+ <%= image_tag(recipe.image_url(:medium))%> +
<%= link_to "Remove from cookbook", remove_recipe_path(recipe.id), class:"btn btn-danger" %> +
+ <% end %> +
+
diff --git a/app/views/home/index.html.erb b/app/views/home/index.html.erb new file mode 100644 index 00000000..bce46c09 --- /dev/null +++ b/app/views/home/index.html.erb @@ -0,0 +1,16 @@ +
+ +

Welcome to Recipe Picker

+

The home for Recipes

+ +

Here are a few recipes to check out!

+
+ <% @recipes.each do |recipe| %> +
+ + <%= link_to recipe.name, recipe_path(recipe.id) %> + +

<%= recipe.description %>

+
+ <% end %> +
diff --git a/app/views/ingredients/edit.html.erb b/app/views/ingredients/edit.html.erb new file mode 100644 index 00000000..dadaa6bc --- /dev/null +++ b/app/views/ingredients/edit.html.erb @@ -0,0 +1,19 @@ +
+ <%= form_for @ingredient, html: {class: "form-group"} do |f| %> +
+ <% flash.each do|name, message| %> +
<%= message %>
+ <% end %> +
+

Edit Your Recipe

+ <%= f.label :name, "Recipe Name" %> + <%= f.text_field :name, class: "form-control" %> +
+ <%= f.label :image, 'Photo' %> + <%= f.file_field :image, class: "form-control" %> +
+
+ <%= f.submit "Submit", class: "btn btn-default"%> +
+ <% end %> +
diff --git a/app/views/ingredients/index.html.erb b/app/views/ingredients/index.html.erb new file mode 100644 index 00000000..3368bcd9 --- /dev/null +++ b/app/views/ingredients/index.html.erb @@ -0,0 +1,6 @@ +
+ + <%= render partial: "shared/index", locals: { collection: @ingredients, link: "ingredients" } %> + + +
diff --git a/app/views/ingredients/new.html.erb b/app/views/ingredients/new.html.erb new file mode 100644 index 00000000..889da672 --- /dev/null +++ b/app/views/ingredients/new.html.erb @@ -0,0 +1,21 @@ +
+ + <%= form_for @ingredient, html: {class: "form-group"}, method: :post do |f| %> +
+ + <% flash.each do|name, message| %> +
<%= message %>
+ <% end %> +
+

Add an Ingredient!

+ <%= f.label :name, "Ingredient Name" %> + <%= f.text_field :name, class: "form-control" %> + + <%= f.label :image, 'Photo' %> + <%= f.file_field :image, class: "form-control" %> +
+
+ <%= f.submit "Submit", class: "btn btn-default"%> +
+ <% end %> +
diff --git a/app/views/ingredients/show.html.erb b/app/views/ingredients/show.html.erb new file mode 100644 index 00000000..479a4291 --- /dev/null +++ b/app/views/ingredients/show.html.erb @@ -0,0 +1,18 @@ +
+

<%= @ingredient.name %> Details

+ + + + + + + + + + + +
NameRecipes
<%= image_tag(@ingredient.image_url(:medium))%> <%= @ingredient.name %><% @ingredient.recipes.each do |recipe| %> +

<%= link_to "#{recipe.name}", recipe_path(recipe.id) %>

+ <% end %> +
+
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 21fbaeb1..362d78c0 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -7,8 +7,10 @@ <%= csrf_meta_tags %> - -<%= yield %> - +
+ <%= render "shared/nav" %> + <%= yield %> + <%= render "shared/footer" %> +
diff --git a/app/views/recipes/add.html.erb b/app/views/recipes/add.html.erb new file mode 100644 index 00000000..7894d325 --- /dev/null +++ b/app/views/recipes/add.html.erb @@ -0,0 +1,15 @@ + +<%= form_for @recipe, html: {class: "form-group"}, method: :patch do |f| %> +
+
+

Add a Recipe!

+ <%= f.label :cookbooks, "Choose a Cookbook!" %>
+ <%= collection_check_boxes(:recipe, :cookbook_ids, @cookbook, :id, :name) do |b| %> + <%= b.label class: "checkbox-inline" do %> + <%= b.check_box + b.text.capitalize %> + <% end %> + <% end %> +
+ <%= f.submit "Submit", class: "btn btn-default"%> +
+ <% end %> diff --git a/app/views/recipes/edit.html.erb b/app/views/recipes/edit.html.erb new file mode 100644 index 00000000..14a84823 --- /dev/null +++ b/app/views/recipes/edit.html.erb @@ -0,0 +1,32 @@ + +<%= form_for @recipe, html: {class: "form-group"} do |f| %> +
+
+

Edit Your Recipe

+ <%= f.label :name, "Recipe Name" %> + <%= f.text_field :name %> + + <%= f.label :description, "Describe Your Recipe" %> + <%= f.text_area :description %> + + <%= f.hidden_field :user_id, value: @recipe.user_id %> + + <%= f.label :preparation, "Preparation" %> + <%= f.text_area :preparation %> +
+ <%= f.label :ingredients, :required => true %>
+ <%= collection_check_boxes(:recipe, :ingredient_ids, Ingredient.all, :id, :name) do |b| %> + <%= b.label class: "checkbox-inline" do %> + <%= b.check_box + b.text.capitalize %> + <% end %> + <% end %> +
+ <%= link_to "Add New Ingredient", new_ingredient_path, class:"btn btn-default" %> +
+ <%= f.label :image, 'Photo' %> + <%= f.file_field :image %> +
+
+ <%= f.submit "Submit", class: "btn btn-default"%> +
+ <% end %> diff --git a/app/views/recipes/index.html.erb b/app/views/recipes/index.html.erb new file mode 100644 index 00000000..ac8cfa37 --- /dev/null +++ b/app/views/recipes/index.html.erb @@ -0,0 +1,11 @@ +
+


+ <%= form_tag(recipes_path, :method => "get", class: "navbar-form", id: "search-form") do %> +
+ <%= text_field_tag :search, params[:search], class: "span2", placeholder: "Search Recipes" %> + +
+ <% end %> + + <%= render partial: "shared/index", locals: { collection: @recipes, link: "recipes" } %> +
diff --git a/app/views/recipes/new.html.erb b/app/views/recipes/new.html.erb new file mode 100644 index 00000000..1323b0a2 --- /dev/null +++ b/app/views/recipes/new.html.erb @@ -0,0 +1,40 @@ +
+ + <%= form_for @recipe, html: {class: "form-group"}, method: :post do |f| %> +
+
+

Add a Recipe!

+ <%= f.label :name, "Recipe Name" %> + <%= f.text_field :name, class: "form-control" %> + + <%= f.label :description, "Describe Your Recipe" %> + <%= f.text_area :description, class: "form-control" %> + + <%= f.hidden_field :user_id, value: @recipe.user_id %> + + <%= f.label :preparation, "Preparation" %> + <%= f.text_area :preparation, class: "form-control" %> +
+ <%= f.label :ingredients, :required => true %>
+ <%= collection_check_boxes(:recipe, :ingredient_ids, Ingredient.all, :id, :name) do |b| %> + <%= b.label class: "checkbox-inline" do %> + <%= b.check_box + b.text.capitalize %> + <% end %> + <% end %> +
+ <%= link_to "Add New Ingredient", new_ingredient_path, class:"btn btn-default" %> +
+ <%= f.label :image, 'Photo' %> + <%= f.file_field :image %> +
+ <%= f.label :cookbooks, "Associate One of Your Cookbooks" %>
+ <%= collection_check_boxes(:recipe, :cookbook_ids, @cookbook, :id, :name) do |b| %> + <%= b.label class: "checkbox-inline" do %> + <%= b.check_box + b.text.capitalize %> + <% end %> + <% end %> +
+ <%= f.submit "Submit", class: "btn btn-primary"%> +
+ <% end %> +
diff --git a/app/views/recipes/results.html.erb b/app/views/recipes/results.html.erb new file mode 100644 index 00000000..63606139 --- /dev/null +++ b/app/views/recipes/results.html.erb @@ -0,0 +1,17 @@ +
+ +

Search Results for <%= params[:search] %>

+<% @recipes.each do |recipe| %> + +<% end %> + + <%= form_tag(recipes_path, :method => "get", class: "navbar-form", id: "search-form") do %> +
+ <%= text_field_tag :search, params[:search], class: "span2", placeholder: "Search Recipes" %> + +
+ <% end %> +
diff --git a/app/views/recipes/show.html.erb b/app/views/recipes/show.html.erb new file mode 100644 index 00000000..276e9f65 --- /dev/null +++ b/app/views/recipes/show.html.erb @@ -0,0 +1,27 @@ + +

<%= @recipe.name %> Details

+

By <%= link_to "#{@user_recipes}", view_user_path(@recipe.user_id) %>

+ +<% if @your_cookbook %> +

<%= button_to "Add it to One of yo Cookbookz!", add_path(@recipe.id), method: "get", class: "btn btn-danger" %>

+<% end %> + + + + + + + + + + + + + + + +
PictureIngredientsDescriptionPreparation
<%= image_tag(@recipe.image_url(:medium))%> <% @recipe.ingredients.each do |ingred| %> +

<%= link_to "#{ingred.name}", ingredient_path(ingred.id) %>

+ <% end %> +
<%= @recipe.description %> <%= @recipe.preparation %>
+
diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb new file mode 100644 index 00000000..95a58b58 --- /dev/null +++ b/app/views/sessions/new.html.erb @@ -0,0 +1,20 @@ +

Log In Page

+ +<% if flash.now[:error] %> +
+ <%=flash.now[:error] %> +
+<%end%> + + +<%= form_for(:session, url: login_path) do |f| %> +
+ <%= f.label :username %> + <%= f.text_field :username, class: "form-control" %> + + <%= f.label :password %> + <%= f.password_field :password, class: "form-control"%> +
+ <%= f.submit "Sign In", class: "btn btn-default" %> +
+<% end %> diff --git a/app/views/shared/_footer.html.erb b/app/views/shared/_footer.html.erb new file mode 100644 index 00000000..f2ba9523 --- /dev/null +++ b/app/views/shared/_footer.html.erb @@ -0,0 +1,7 @@ + diff --git a/app/views/shared/_index.html.erb b/app/views/shared/_index.html.erb new file mode 100644 index 00000000..18af8acb --- /dev/null +++ b/app/views/shared/_index.html.erb @@ -0,0 +1,10 @@ +

All the <%= collection.name.pluralize %>

+ +
+ <% collection.each do |separate| %> +
+
<%= image_tag(separate.image_url)%>
+

<%= link_to separate.name, "/#{link}/#{separate.id}", method: :get %>

+
+ <% end %> +
diff --git a/app/views/shared/_nav.html.erb b/app/views/shared/_nav.html.erb new file mode 100644 index 00000000..c0ff08ff --- /dev/null +++ b/app/views/shared/_nav.html.erb @@ -0,0 +1,22 @@ + diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb new file mode 100644 index 00000000..639c53e4 --- /dev/null +++ b/app/views/users/new.html.erb @@ -0,0 +1,16 @@ +

Register with us!

+<%= form_for @user do |f| %> +
+ <%= f.label :username, "User Name" %> + <%= f.text_field :username, class: "form-control" %> + + <%= f.label :password, "Password" %> + <%= f.password_field :password, class: "form-control"%> + + <%= f.label :password_confirmation, "Password Confirmation" %> + <%= f.password_field :password_confirmation, class: "form-control" %> + +
+ <%= f.submit "Submit", class: "btn btn-default" %> +
+<% end %> diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb new file mode 100644 index 00000000..286b7108 --- /dev/null +++ b/app/views/users/show.html.erb @@ -0,0 +1,67 @@ +
+

<%= @user.username %>'s Dashboard

+ <%= button_to "New Recipe", new_recipe_path, method: :get, class: "btn btn-default" %> + <%= button_to "New Ingredient", new_ingredient_path, method: :get, class: "btn btn-default" %> + <%= button_to "New Cookbook", new_cookbook_path, method: :get, class: "btn btn-default" %> + + + + + + + + + + <% @cookbooks.each do |cookbook| %> + + + + + + + + +<% end %> +
Your CookbooksDescriptionNo. RecipesNo. Unique IngredientsDelete?

<%= link_to "#{cookbook.name}", cookbook_path(cookbook.id) %>

<%= cookbook.description %><%= cookbook.recipes.count %>
    + <%= cookbook.recipes.flat_map {|cookbook_recipes| cookbook_recipes.ingredients.pluck(:name)}.uniq.count %> +
<%= button_to "Delete", cookbook_path(cookbook.id), method: "delete", class: "btn btn-danger" %>
+ + + + + + + + + <% @recipes.each do |recipe| %> + + + + + + <% end %> + +
Your RecipesEdit!Delete?
+ <%= image_tag(recipe.image_url(:thumb))%> + <%= link_to "#{recipe.name}", recipe_path(recipe.id)%> + <%= button_to "Edit", edit_recipe_path(recipe.id), method: "get", class: "btn btn-danger" %><%= button_to "Delete", recipe_path(recipe.id), method: "delete", class: "btn btn-danger" %>
+ + + + + + + + + <% @ingredients.each do |ingredient| %> + + + + + + <% end %> +
Your IngredientsEdit!Delete?
<%= link_to "#{ingredient.name}", ingredient_path(ingredient.id)%><%= button_to "Edit", edit_ingredient_path(ingredient.id), method: "get", class: "btn btn-danger" %><%= button_to "Delete", ingredient_path(ingredient.id), method: "delete", class: "btn btn-danger" %>
+ + + +
diff --git a/app/views/users/view.html.erb b/app/views/users/view.html.erb new file mode 100644 index 00000000..213bfd38 --- /dev/null +++ b/app/views/users/view.html.erb @@ -0,0 +1,13 @@ +
+

<%= @user.username %> has <%= @user.recipes.count %> Recipes

+
+ +
+
diff --git a/config/routes.rb b/config/routes.rb index 3f66539d..f07b6730 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,7 +3,22 @@ # See how all your routes lay out with "rake routes". # You can have the root of your site routed with "root" - # root 'welcome#index' + root 'home#index' + + # sessions paths + get "/signup" => 'users#new', as: 'signup' + get "/login", to: "sessions#new", as: 'login' + post "/login", to: "sessions#create" + delete "/logout", to: "sessions#destroy", as: 'logout' + get "/remove/recipe/:recipe_id", to: "recipes#remove_recipe", as: 'remove_recipe' + + + resources :recipes + resources :cookbooks + resources :ingredients + resources :users, except: [:new] + get "/view_users/:id" => "users#view", as: 'view_user' + get "/recipes/:id/add" => "recipes#add", as: 'add' # Example of regular route: # get 'products/:id' => 'catalog#view' diff --git a/db/migrate/20150728185909_create_recipes.rb b/db/migrate/20150728185909_create_recipes.rb new file mode 100644 index 00000000..4b39abac --- /dev/null +++ b/db/migrate/20150728185909_create_recipes.rb @@ -0,0 +1,8 @@ +class CreateRecipes < ActiveRecord::Migration + def change + create_table :recipes do |t| + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20150728185924_create_ingredients.rb b/db/migrate/20150728185924_create_ingredients.rb new file mode 100644 index 00000000..c7280337 --- /dev/null +++ b/db/migrate/20150728185924_create_ingredients.rb @@ -0,0 +1,8 @@ +class CreateIngredients < ActiveRecord::Migration + def change + create_table :ingredients do |t| + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20150728190914_add_columns_to_recipe_table.rb b/db/migrate/20150728190914_add_columns_to_recipe_table.rb new file mode 100644 index 00000000..1f914258 --- /dev/null +++ b/db/migrate/20150728190914_add_columns_to_recipe_table.rb @@ -0,0 +1,8 @@ +class AddColumnsToRecipeTable < ActiveRecord::Migration + def change + add_column :recipes, :name, :string + add_column :recipes, :description, :string + add_column :recipes, :preparation, :string + add_column :recipes, :user_id, :integer + end +end diff --git a/db/migrate/20150728190926_add_columns_to_ingredient_table.rb b/db/migrate/20150728190926_add_columns_to_ingredient_table.rb new file mode 100644 index 00000000..71569ed2 --- /dev/null +++ b/db/migrate/20150728190926_add_columns_to_ingredient_table.rb @@ -0,0 +1,5 @@ +class AddColumnsToIngredientTable < ActiveRecord::Migration + def change + add_column :ingredients, :name, :string + end +end diff --git a/db/migrate/20150728205716_create_users.rb b/db/migrate/20150728205716_create_users.rb new file mode 100644 index 00000000..e362034b --- /dev/null +++ b/db/migrate/20150728205716_create_users.rb @@ -0,0 +1,9 @@ +class CreateUsers < ActiveRecord::Migration + def change + create_table :users do |t| + t.string :username, null: false + t.string :password_digest, null: false + t.timestamps null: false + end + end +end diff --git a/db/migrate/20150728205722_create_cookbooks.rb b/db/migrate/20150728205722_create_cookbooks.rb new file mode 100644 index 00000000..41ca2df9 --- /dev/null +++ b/db/migrate/20150728205722_create_cookbooks.rb @@ -0,0 +1,10 @@ +class CreateCookbooks < ActiveRecord::Migration + def change + create_table :cookbooks do |t| + t.string :name, null: false + t.string :description + t.string :user_id, null: false + t.timestamps null: false + end + end +end diff --git a/db/migrate/20150728212006_cookbooks_recipes.rb b/db/migrate/20150728212006_cookbooks_recipes.rb new file mode 100644 index 00000000..9a3de891 --- /dev/null +++ b/db/migrate/20150728212006_cookbooks_recipes.rb @@ -0,0 +1,8 @@ +class CookbooksRecipes < ActiveRecord::Migration + def change + create_table :cookbooks_recipes, id: false do |t| + t.belongs_to :cookbook, index: true + t.belongs_to :recipe, index: true + end + end +end diff --git a/db/migrate/20150728223622_ingredients_recipes.rb b/db/migrate/20150728223622_ingredients_recipes.rb new file mode 100644 index 00000000..a0702090 --- /dev/null +++ b/db/migrate/20150728223622_ingredients_recipes.rb @@ -0,0 +1,8 @@ +class IngredientsRecipes < ActiveRecord::Migration + def change + create_table :ingredients_recipes, id: false do |t| + t.belongs_to :ingredient, index: true + t.belongs_to :recipe, index: true + end + end +end diff --git a/db/migrate/20150728224357_remove_null_from_columns.rb b/db/migrate/20150728224357_remove_null_from_columns.rb new file mode 100644 index 00000000..a340d0e4 --- /dev/null +++ b/db/migrate/20150728224357_remove_null_from_columns.rb @@ -0,0 +1,6 @@ +class RemoveNullFromColumns < ActiveRecord::Migration + def change + change_column :users, :username, :string, :null => true + change_column :users, :password_digest, :string, :null => true + end +end diff --git a/db/migrate/20150729012804_make_null_true_cookbook.rb b/db/migrate/20150729012804_make_null_true_cookbook.rb new file mode 100644 index 00000000..05e1a9c8 --- /dev/null +++ b/db/migrate/20150729012804_make_null_true_cookbook.rb @@ -0,0 +1,6 @@ +class MakeNullTrueCookbook < ActiveRecord::Migration + def change + change_column :cookbooks, :name, :string, :null => true + change_column :cookbooks, :user_id, :integer, :null => true + end +end diff --git a/db/migrate/20150730135259_add_image_to_recipes.rb b/db/migrate/20150730135259_add_image_to_recipes.rb new file mode 100644 index 00000000..032591e4 --- /dev/null +++ b/db/migrate/20150730135259_add_image_to_recipes.rb @@ -0,0 +1,5 @@ +class AddImageToRecipes < ActiveRecord::Migration + def change + add_column :recipes, :image, :string + end +end diff --git a/db/migrate/20150730155559_add_image_to_ingredients.rb b/db/migrate/20150730155559_add_image_to_ingredients.rb new file mode 100644 index 00000000..e1a4db98 --- /dev/null +++ b/db/migrate/20150730155559_add_image_to_ingredients.rb @@ -0,0 +1,5 @@ +class AddImageToIngredients < ActiveRecord::Migration + def change + add_column :ingredients, :image, :string + end +end diff --git a/db/migrate/20150731050719_add_column_to_ingredients.rb b/db/migrate/20150731050719_add_column_to_ingredients.rb new file mode 100644 index 00000000..69b68e5b --- /dev/null +++ b/db/migrate/20150731050719_add_column_to_ingredients.rb @@ -0,0 +1,5 @@ +class AddColumnToIngredients < ActiveRecord::Migration + def change + add_column :ingredients, :user_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 00000000..6924a83c --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,65 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 20150731050719) do + + create_table "cookbooks", force: :cascade do |t| + t.string "name" + t.string "description" + t.integer "user_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "cookbooks_recipes", id: false, force: :cascade do |t| + t.integer "cookbook_id" + t.integer "recipe_id" + end + + add_index "cookbooks_recipes", ["cookbook_id"], name: "index_cookbooks_recipes_on_cookbook_id" + add_index "cookbooks_recipes", ["recipe_id"], name: "index_cookbooks_recipes_on_recipe_id" + + create_table "ingredients", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "name" + t.string "image" + t.integer "user_id" + end + + create_table "ingredients_recipes", id: false, force: :cascade do |t| + t.integer "ingredient_id" + t.integer "recipe_id" + end + + add_index "ingredients_recipes", ["ingredient_id"], name: "index_ingredients_recipes_on_ingredient_id" + add_index "ingredients_recipes", ["recipe_id"], name: "index_ingredients_recipes_on_recipe_id" + + create_table "recipes", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "name" + t.string "description" + t.string "preparation" + t.integer "user_id" + t.string "image" + end + + create_table "users", force: :cascade do |t| + t.string "username" + t.string "password_digest" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + +end diff --git a/db/seeds.rb b/db/seeds.rb index 4edb1e85..2476a7ed 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,7 +1,198 @@ # This file should contain all the record creation needed to seed the database with its default values. # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). # -# Examples: -# -# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) -# Mayor.create(name: 'Emanuel', city: cities.first) + +cookbooks = [ + { + name: "Dessert", + description: "The best desserts from around our corner of the internet", + user_id: 1 + }, + { + name: "My Favorites", + description: "These are some of my favorite things", + user_id: 2 + } +] + +cookbooks.each do |book| + Cookbook.create book +end +# Users ------------------------------- +users = [ + {username: "wangg", password_digest: 1234}, + {username: "brittz", password_digest: 1234} + # when seeding users, store pw as 'password_digest' +] + +users.each do |user| + User.create user +end + +# Recipes ------------------------------- +recipes = [ + + { + name: "Chocolate Coconut Milk Ice Cream", + description: "Healthy yet decadent", + preparation: "Combine all of the ingredients in a blender, and blend until smooth and creamy. Adjust the flavor to your taste, then transfer to a freezer-safe container. Place in the freezer for 4-6 hours, or until firm.", + user_id: 2, + image: "choc_ice_cream.jpg" + }, + + { + name: "Yam Chips", + description: "Yam Chips", + preparation: "Slice yam in thin slices using mandolin. Toss with rest of ingredients. Lay flat on foil and put it in the oven. Bake until crispy.", + user_id: 1, + image: "yam_chips.jpg" + }, + + { + name: "Salsa Chicken", + description: "Quick and easy mexican style crock pot recipe", + preparation: "Add Chicken to crock pot, and all other ingredients on top. Cook on low for 6 hours", + user_id: 2, + image: "black_pepper.jpg" + }, + + { + name: "Witches Brew", + description: "For a spooky halloween night", + preparation: "Combine mud and water until desired consistency. Add grass and earthworms as a garnish.", + user_id: 1, + image: "pineapple.jpg" + }, + + { + name: "Soft Chocolate Chip Cookies", + description: "Very delicious, you can use any flavor pudding you like for this recipe.", + preparation: "Preheat oven to 350 degrees F (175 degrees C). Sift together the flour and baking soda, set aside. In a large bowl, cream together the butter, brown sugar, and white sugar. Beat in the instant pudding mix until blended. Stir in the eggs and vanilla. Blend in the flour Bake for 10 to 12 minutes in the preheated oven. Edges should be golden brown.mixture. Finally, stir in the chocolate chips and nuts. Drop cookies by rounded spoonfuls onto ungreased cookie sheets.", + user_id: 2, + image: "fake_reeses.jpg" + }, + + { + name: "Peanut Butter & Jam Sando", + description: "The golden oldie; never gets old", + preparation: "Apply peanut butter to one piece of bread. Add jam to the top to desired height. Enjoy.", + user_id: 1, + image: "yam.jpg" + }, + + { + name: "Fried Chicken", + description: "Finger licking-greasy good", + preparation: "Heat oil in deep fryer, apply batter to chicken until coated. Add to fryer until golden brown. Towel dry.", + user_id: 2, + image: "yam.jpg" + } + +] + + +recipes.each do |recipe| + + image_path = "app/assets/images/" + recipe[:image] + + x = Recipe.new( + name: recipe[:name], + description: recipe[:description], + preparation: recipe[:preparation], + user_id: recipe[:user_id], + image: open(image_path) + ) + + x.save(validate: false ) + +end + +# Ingredients ------------------------------- + +ingredients = [ + + {name: "Coconut Milk", image: "coconut_milk.jpg", user_id: 2}, + {name: "Cocoa Powder", image: "cocoa-powder.jpg", user_id: 2}, + {name: "Honey", user_id: 2}, + {name: "Almond Butter", user_id: 2}, + {name: "Yams", image: "yam.jpg", user_id: 2}, + {name: "Vanilla Extract", user_id: 2}, + {name: "Chicken", user_id: 1}, + {name: "Salsa", user_id: 1}, + {name: "Peanut Butter", user_id: 1}, + {name: "Bread", user_id: 1}, + {name: "Jam", user_id: 1}, + {name: "Mud", user_id: 1}, + {name: "Water", user_id: 1}, + {name: "Grass", user_id: 1}, + {name: "Chocolate Chip", user_id: 1}, + {name: "Flour", user_id: 1}, + {name: "Baking Powder", user_id: 1}, + {name: "Oil", image: "olive-oil.jpg", user_id: 1} + +] +i = {} +ingredients.each do |ingredient| + ar_obj = Ingredient.new ingredient + ar_obj.save(validate: false) + i[ar_obj.name] = ar_obj.id + # key = "honey", value = honey id +end + +# recipe-ingredient Join Table ------------------------------- + +recipe = Recipe.find(1) +# Chocolate Coconut Milk Ice Cream +recipe.ingredients << Ingredient.find(i["Honey"]) +recipe.ingredients << Ingredient.find(i["Coconut Milk"]) +recipe.ingredients << Ingredient.find(i["Cocoa Powder"]) +recipe.ingredients << Ingredient.find(i["Almond Butter"]) +recipe.ingredients << Ingredient.find(i["Vanilla Extract"]) + +recipe = Recipe.find(2) +# Yam Chips +recipe.ingredients << Ingredient.find(i["Yams"]) + +recipe = Recipe.find(3) +# Salsa Chicken +recipe.ingredients << Ingredient.find(i["Chicken"]) +recipe.ingredients << Ingredient.find(i["Salsa"]) + +recipe = Recipe.find(4) +# Witches Brew +recipe.ingredients << Ingredient.find(i["Mud"]) +recipe.ingredients << Ingredient.find(i["Water"]) +recipe.ingredients << Ingredient.find(i["Grass"]) + +recipe = Recipe.find(5) +# Soft Chocolate Chip Cookies +recipe.ingredients << Ingredient.find(i["Chocolate Chip"]) +recipe.ingredients << Ingredient.find(i["Flour"]) +recipe.ingredients << Ingredient.find(i["Baking Powder"]) +recipe.ingredients << Ingredient.find(i["Oil"]) + +recipe = Recipe.find(6) +# Peanut Butter & Jam Sando +recipe.ingredients << Ingredient.find(i["Peanut Butter"]) +recipe.ingredients << Ingredient.find(i["Jam"]) +recipe.ingredients << Ingredient.find(i["Bread"]) + + +recipe = Recipe.find(7) +# Fried Chicken +recipe.ingredients << Ingredient.find(i["Chicken"]) +recipe.ingredients << Ingredient.find(i["Oil"]) + +# cookbook-recipe Join Table ------------------------------- + +book = Cookbook.find(1) +# Dessert +book.recipes << Recipe.find(1) +book.recipes << Recipe.find(2) +book.recipes << Recipe.find(5) +book.recipes << Recipe.find(6) + +book = Cookbook.find(2) +# My Favorites +book.recipes << Recipe.find(3) +book.recipes << Recipe.find(4) diff --git a/scaffold.md b/scaffold.md index a1cc385a..37e9d1bd 100644 --- a/scaffold.md +++ b/scaffold.md @@ -28,3 +28,4 @@ Recipes Cookbooks Users Sessions +Home diff --git a/spec/controllers/cookbooks_controller_spec.rb b/spec/controllers/cookbooks_controller_spec.rb new file mode 100644 index 00000000..5e29b5ea --- /dev/null +++ b/spec/controllers/cookbooks_controller_spec.rb @@ -0,0 +1,134 @@ +require 'rails_helper' + +RSpec.describe CookbooksController, type: :controller do + + describe "GET #show" do + before(:each) do + soup = create :recipe, ingredients: [create(:ingredient)] + @cookbook = create :cookbook, user: create(:user), recipes: [soup] + session[:user_id] = @cookbook.user_id + end + + it "returns successfully with HTTP code of 200" do + get :show, id: @cookbook + # why is this returning false? + expect(response).to be_success + end + + it "renders the :show view" do + get :show, id: @cookbook + expect(response).to render_template(:show) + end + + it "finds the right cookbook" do + get :show, id: @cookbook + expect{assigns(book).to eq(Cookbook)} + end + end + + describe "GET #new" do + let(:book) {create :cookbook} + + it "creates a new cookbook" do + get :new + expect(assigns(:cookbook)).to be_a_new(Cookbook) + expect(response).to render_template(:new) + end + end + + describe "POST #create" do + # + test case + it "creates a new Cookbook record" do + session[:user_id] = 20 + expect{post :create, cookbook: FactoryGirl.attributes_for(:cookbook)}.to change(Cookbook, :count).by(1) + end + # - test case + context "doesn't let invalid cookbooks to save" do + it "does not persist invalid ingredients" do + session[:user_id] = 20 + + expect{post :create, cookbook: FactoryGirl.attributes_for(:cookbook, name: nil)}.to change(Cookbook, :count).by(0) + end + + it "renders the :new view (to allow users to fix invalid data)" do + post :create, cookbook: FactoryGirl.attributes_for(:cookbook, name: nil) + expect(response).to render_template("new") + end + + end + end # create + + describe "GET #edit" do + # + test case + context "it's the user's cookbook" do + before(:each) do + soup = create :recipe, ingredients: [create(:ingredient)] + @cookbook = create :cookbook, user: create(:user), recipes: [soup] + session[:user_id] = @cookbook.user_id + end + it "renders the edit page" do + get :edit, id: @cookbook + expect(response).to render_template(:edit) + end + end + # - test case + context "it's not user's cookbook" do + before(:each) do + soup = create :recipe, ingredients: [create(:ingredient)] + @cookbook = create :cookbook, user: create(:user), recipes: [soup] + session[:user_id] = 20 + end + it "redirect_to user_path" do + get :edit, id: @cookbook + expect(response).to redirect_to(user_path(session[:user_id])) + # undefined method `user_id' for nil:NilClass?? + end + end + end + + describe "PATCH #update" do + context "sucessful update" do + before(:each) do + soup = create :recipe, ingredients: [create(:ingredient)] + @cookbook = create :cookbook, user: create(:user), recipes: [soup] + session[:user_id] = @cookbook.user_id + end + + it "changes cookbook name" do + patch :update, :id => @cookbook, :cookbook => {name: "Cookbookin'"} + @cookbook.reload + expect(@cookbook.name).to eq("Cookbookin'") + end + + it "redirect_to user_path" do + patch :update, id: @cookbook, :cookbook => {name: "Cookbookin'"} + expect(response).to redirect_to(user_path(@cookbook.user_id)) + end + + end + end + + describe "DELETE #destroy" do + before(:each) do + soup = create :recipe, ingredients: [create(:ingredient)] + @cookbook = create :cookbook, user: create(:user), recipes: [soup] + session[:user_id] = @cookbook.user_id + end + + it "cookbook count changes by -1" do + expect{delete :destroy, {id: @cookbook}}.to change(Cookbook, :count).by(-1) + end + + it "redirect_to user_path" do + delete :destroy, id: @cookbook + expect(response).to redirect_to(user_path(@cookbook.user_id)) + end + + it "doesn't delete the recipe" do + delete :destroy, id: @cookbook + expect(Recipe.count).to eq(1) + end + end + + +end diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb new file mode 100644 index 00000000..b95e04f2 --- /dev/null +++ b/spec/controllers/home_controller_spec.rb @@ -0,0 +1,11 @@ +require 'rails_helper' + +RSpec.describe HomeController, type: :controller do + describe "GET #index" do + it "renders the index template" do + get :index + expect(response).to render_template("index") + end + end + +end diff --git a/spec/controllers/ingredients_controller_spec.rb b/spec/controllers/ingredients_controller_spec.rb new file mode 100644 index 00000000..d15c89e8 --- /dev/null +++ b/spec/controllers/ingredients_controller_spec.rb @@ -0,0 +1,156 @@ +require 'rails_helper' + +RSpec.describe IngredientsController, type: :controller do + describe "GET #index" do + it "renders the index template" do + get :index + expect(response).to render_template("index") + end + end # index + + describe "GET #show" do + let(:pineapple) {create :ingredient} + + it "returns successfully with HTTP code of 200" do + get :show, id: pineapple + expect(response).to be_success + end + + it "renders the :show view" do + get :show, id: pineapple + expect(response).to render_template(:show) + end + end #show + + describe "GET #new" do + let(:pineapple) {create :ingredient} + + it "creates a new ingredient" do + session[:user_id] = create(:ingredient) + get :new, :id => session[:user_id] + expect(assigns(:ingredient)).to be_a_new(Ingredient) + expect(response).to render_template(:new) + end + end # new + + describe "POST #create" do + # + test case + context "Valid Ingredient params" do + let(:ingred_params) do + { + ingredient: { + name: 'Steak', + image: 'steak.jpg' + } + } + end + + it "creates a new Ingredient record" do + post :create, ingred_params + expect(Ingredient.count).to eq(1) + end + end + # - test case + context "Invalid Ingredient params" do + let(:ingred_params) do + { + ingredient: { + image: 'steak.jpg' + } + } + end + + it "does not persist invalid ingredients" do + post :create, ingred_params + expect(Ingredient.count).to eq 0 + end + + it "renders the :new view (to allow users to fix invalid data)" do + post :create, ingred_params + expect(response).to render_template("new") + end + + end + end + + describe "GET #edit" do + # + test case + context "it's the user's ingredient" do + before(:each) do + @yams = create :ingredient, user: create(:user) + session[:user_id] = @yams.user_id + end + + it "renders the edit page" do + get :edit, id: @yams + expect(response).to render_template(:edit) + end + end + # - test case + context "it's not user's ingredient" do + before(:each) do + @yams = create :ingredient, user: create(:user) + session[:user_id] != @yams.user_id + end + + it "redirect_to ingredient_path" do + get :edit, id: @yams + expect(response).to redirect_to(ingredient_path(@yams)) + # undefined method `user_id' for nil:NilClass?? + end + end + end + + describe "PATCH #update" do + context "sucessful update" do + before(:each) do + @yams = create :ingredient, user: create(:user) + session[:user_id] = @yams.user_id + end + + it "changes recipe's name" do + patch :update, :id => @yams, :ingredient => {name: "sweet potatoez"} + @yams.reload + expect(@yams.name).to eq("sweet potatoez") + end + + it "redirect_to user_path" do + patch :update, id: @yams, :ingredient => {name: "sweet potatoez"} + expect(response).to redirect_to(user_path(@yams.user_id)) + end + end + + context "unsucessful update" do + before(:each) do + @yams = create :ingredient, user: create(:user) + session[:user_id] = @yams.user_id + end + + it "renders edit form if unsuccessful update" do + patch :update, :id => @yams, :ingredient => {name: nil} + @yams.reload + expect(@yams).to render_template(:edit) + end + end + + end + + + describe "DELETE #destroy" do + before(:each) do + @pine = create :ingredient + @pop = create :ingredient, name: "PopTarts" + session[:user_id] = 20 + end + + it "ingredient count changes by -1" do + expect{delete :destroy, {id: @pine.id}}.to change(Ingredient, :count).by(-1) + end + + it "redirect_to root_path" do + delete :destroy, id: @pine.id + expect(response).to redirect_to(user_path(session[:user_id])) + end + end # destroy + +end # describe diff --git a/spec/controllers/recipes_controller_spec.rb b/spec/controllers/recipes_controller_spec.rb new file mode 100644 index 00000000..da529a07 --- /dev/null +++ b/spec/controllers/recipes_controller_spec.rb @@ -0,0 +1,195 @@ +require 'rails_helper' + +RSpec.describe RecipesController, type: :controller do + + describe "GET #index" do + let(:recipe_params) do + { + recipe: { + name: "Yay", + preparation: "Yup", + ingredient_ids: 2, + user_id: 1 + } + } + end + + it "renders the index template" do + get :index, recipe_params + expect(response).to render_template("index") + end + end + + describe "GET #show" do + + before(:each) do + @soup = create :recipe, ingredients: [create(:ingredient)], user: create(:user) + end + + it "returns successfully with HTTP code of 200" do + get :show, id: @soup + expect(response).to be_success + end + + it "renders the :show view" do + get :show, id: @soup + expect(response).to render_template(:show) + end + end + + describe "GET #remove_recipe" do + # creating a cookbook associated with a user, and associated with recipes collection + # let(:book) { create :cookbook, user: create(:user), recipes: [create(:recipe)] } + + before(:each) do + soup = create :recipe, ingredients: [create(:ingredient)] + @book = create :cookbook, user: create(:user), recipes: [soup] + # need a cookbook_id in session for method to work + session[:cookbook_id] = @book.id + end + + it "removes recipe from cookbook" do + get :remove_recipe, :recipe_id => 1 + expect(@book.recipes.count).to eq(0) + end + + it "doesn't delete the recipe" do + get :remove_recipe, :recipe_id => 1 + expect(Recipe.count).to eq(1) + end + end + + describe "GET #new" do + let(:recipe_params) do + { + recipe: { + name: "Yay", + preparation: "Yup", + :ingredient_ids => [2], + user_id: 1 + } + } + end + + it "renders the new template" do + session[:user_id] = create(:user) + get :new, :id => session[:user_id] + expect(response).to render_template("new") + end + + it "creates a new Recipe object" do + session[:user_id] = create(:user) + get :new, recipe_params + expect(assigns(:recipe)).to be_kind_of(Object) + end + end + + describe "POST #create" do + + before :each do + user = create :user, id: 2 + session[:user_id] = 2 + ingredient = create(:ingredient) + end + + context "valid params" do + let (:recipe_params) do + { + name: "Yay", + preparation: "yup", + user_id: 2, + :ingredient_ids => [1] + } + end + + it "creates a new Recipe record" do + post :create, recipe: recipe_params + expect(Recipe.count).to eq(1) + end + end + + context "with invalid recipe params" do + let (:invalid_recipe_params) do + { + name: "Some Name", + user_id: 2 } + end + + it "doesn't create a new recipe" do + post :create, :recipe => invalid_recipe_params + expect(response).to render_template(:new) + end + end + end + + describe "GET #edit" do + # + test case + context "it's the user's recipe" do + before(:each) do + @soup = create :recipe, ingredients: [create(:ingredient)], user: create(:user) + session[:user_id] = @soup.user_id + end + + it "renders the edit page" do + get :edit, id: @soup + expect(response).to render_template(:edit) + end + end + # - test case + context "it's not user's recipe" do + before(:each) do + @soup = create :recipe, ingredients: [create(:ingredient)], user: create(:user) + session[:user_id] != @soup.user_id + end + + it "redirect_to recipe_path" do + get :edit, id: @soup + expect(response).to redirect_to(recipe_path(@soup)) + # undefined method `user_id' for nil:NilClass?? + end + end + end + + describe "PATCH #update" do + context "sucessful update" do + before(:each) do + @soup = create :recipe, ingredients: [create(:ingredient)], user: create(:user) + session[:user_id] = @soup.user_id + end + + it "changes recipe's name" do + patch :update, :id => @soup, :recipe => {name: "EAT MOAR SOUPZ"} + @soup.reload + expect(@soup.name).to eq("EAT MOAR SOUPZ") + end + + it "redirect_to user_path" do + patch :update, id: @soup, :recipe => {name: "EAT MOAR SOUPZ"} + expect(response).to redirect_to(user_path(@soup.user_id)) + end + + end + end + + + + + + describe "DELETE #destroy" do + + before(:each) do + @soup = create :recipe, ingredients: [create(:ingredient)], user: create(:user) + session[:user_id] = @soup.user_id + end + + it "ingredient count changes by -1" do + delete :destroy, id: @soup + expect(Recipe.count).to eq(0) + end + + + end + + + +end diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb new file mode 100644 index 00000000..636d1331 --- /dev/null +++ b/spec/controllers/sessions_controller_spec.rb @@ -0,0 +1,53 @@ +require 'rails_helper' + +RSpec.describe SessionsController, type: :controller do + before(:each) do + @user = create(:user) + session[:user_id] = @user.id + end + + describe "POST #create" do + + let (:session_params) do + { + username: "myspacerox", + password: "2002"} + end + + it "creates an authenticated session" do + post :create, :session => session_params + expect(session[:user_id]).to eq(1) + end + end + + + describe "DELETE #destroy" do + it "allows user to log out" do + delete :destroy + expect(session[:user_id]).to eq(nil) + end + end + + # describe "POST #create" do + # + # let (:session_params) { create :session, username: "myspacerox", password: "2002"} + # + # it "creates an authenticated session" do + # user = build :user + # session_params + # post :create, :session => session_params + # + # expect(session[:user_id]).to eq(1) + # end + # end + + + + + + + + + + +end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb new file mode 100644 index 00000000..d9ce948f --- /dev/null +++ b/spec/controllers/users_controller_spec.rb @@ -0,0 +1,64 @@ +require 'rails_helper' + +RSpec.describe UsersController, type: :controller do + describe "GET #new" do + let(:user) {create :user} + + it "creates a new ingredient" do + get :new + expect(assigns(:user)).to be_a_new(User) + expect(response).to render_template(:new) + end + end + + describe "GET #show" do + before :each do + @user = create :user + end + + it "returns http success" do + session[:user_id] = @user.id + get :show, :id => 1 + expect(response).to have_http_status(:success) + end + + it "loads a user into @user" do + session[:user_id] = @user.id + get :show, :id => session[:user_id] + + expect(assigns(:user)).to eq(@user) + end + end + + describe "POST #create" do + context "with valid user params" do + + let (:user_params) do + { + username: "beaverz", + password: "213", + password_confirmation: "213"} + end + + it "creates a new user" do + post :create, :user => user_params + expect(User.count).to eq(1) + end + end + + context "invalid user params" do + let (:bad_user) do + { + username: "Eeeediot", + password: "youu", + password_confirmation: "song"} + end + + it "doesn't create a new user" do + post :create, :user => bad_user + expect(response).to redirect_to(signup_path) + end + end + end + +end diff --git a/spec/factories.rb b/spec/factories.rb index e69de29b..803be33c 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -0,0 +1,28 @@ +FactoryGirl.define do + + factory :ingredient_params do + # can we do this? + end + + factory :user do + username "myspacerox" + password "2002" + password_confirmation "2002" + end + + + factory :recipe do + name "Soup" + preparation "Stir It" + user_id 2 + end + + factory :ingredient do + name "Water" + end + + factory :cookbook do + name "Paula Deen vs Jimmy Dean" + description "This is the ultimate Battle Royale, with CHEESE!" + end +end diff --git a/spec/helpers/cookbooks_helper_spec.rb b/spec/helpers/cookbooks_helper_spec.rb new file mode 100644 index 00000000..032c4c19 --- /dev/null +++ b/spec/helpers/cookbooks_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the CookbooksHelper. For example: +# +# describe CookbooksHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe CookbooksHelper, type: :helper do + +end diff --git a/spec/helpers/home_helper_spec.rb b/spec/helpers/home_helper_spec.rb new file mode 100644 index 00000000..7d55f93d --- /dev/null +++ b/spec/helpers/home_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the HomeHelper. For example: +# +# describe HomeHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe HomeHelper, type: :helper do + +end diff --git a/spec/helpers/ingredients_helper_spec.rb b/spec/helpers/ingredients_helper_spec.rb new file mode 100644 index 00000000..fc5a9d6e --- /dev/null +++ b/spec/helpers/ingredients_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the IngredientsHelper. For example: +# +# describe IngredientsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe IngredientsHelper, type: :helper do + +end diff --git a/spec/helpers/recipes_helper_spec.rb b/spec/helpers/recipes_helper_spec.rb new file mode 100644 index 00000000..ecfe9d8f --- /dev/null +++ b/spec/helpers/recipes_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the RecipesHelper. For example: +# +# describe RecipesHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe RecipesHelper, type: :helper do + +end diff --git a/spec/helpers/sessions_helper_spec.rb b/spec/helpers/sessions_helper_spec.rb new file mode 100644 index 00000000..f0dae30f --- /dev/null +++ b/spec/helpers/sessions_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the SessionsHelper. For example: +# +# describe SessionsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe SessionsHelper, type: :helper do + +end diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb new file mode 100644 index 00000000..10dbece1 --- /dev/null +++ b/spec/helpers/users_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the UsersHelper. For example: +# +# describe UsersHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe UsersHelper, type: :helper do + +end diff --git a/spec/models/cookbook_spec.rb b/spec/models/cookbook_spec.rb new file mode 100644 index 00000000..4e4ccdf1 --- /dev/null +++ b/spec/models/cookbook_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' + +RSpec.describe Cookbook, type: :model do + # + case + it "creates cookbook if name is present" do + cookbook1 = build :cookbook + expect(cookbook1).to be_valid + end + # - case + it "Requires that a name must be present" do + cookbook1 = build :cookbook, name: nil + + expect(cookbook1).to_not be_valid + expect(cookbook1.errors.keys).to include(:name) + end +end diff --git a/spec/models/ingredient_spec.rb b/spec/models/ingredient_spec.rb new file mode 100644 index 00000000..a34ba8fd --- /dev/null +++ b/spec/models/ingredient_spec.rb @@ -0,0 +1,42 @@ +require 'rails_helper' + +RSpec.describe Ingredient, type: :model do + context "name validation" do + let(:pine) {create :ingredient} + let(:pine2) {create :ingredient} + + # + case + it "creates ingredient if name is present" do + expect(pine).to be_valid + end + + # - case + it "requires ingredient name to be present" do + pine = build :ingredient, name: nil + + expect(pine).to_not be_valid + expect(pine.errors.keys).to include(:name) + end + + it "requires a name to be unique" do + pine + another_pine = pine.dup + another_pine.save + + expect(another_pine.errors.keys).to include(:name) + end + end + + describe "alphabet scope" do + let(:ingredient1) { create :ingredient, name: "Jerky"} + let(:ingredient2) { create :ingredient, name: "Bacon"} + let(:ingredient3) { create :ingredient, name: "Pineapple"} + let(:ingredient4) { create :ingredient, name: "Apple"} + + it "orders ingredients alphabetically" do + ingredient2 + order = [ingredient4, ingredient2, ingredient1, ingredient3] + expect(Ingredient.all.alphabet).to eq(order) + end + end +end diff --git a/spec/models/recipe_spec.rb b/spec/models/recipe_spec.rb new file mode 100644 index 00000000..33981bc9 --- /dev/null +++ b/spec/models/recipe_spec.rb @@ -0,0 +1,45 @@ +require 'rails_helper' + +RSpec.describe Recipe, type: :model do + + describe "recipe model validations" do + it "must have one or more order ingredients" do + recipe = build :recipe + ingredient = build :ingredient + recipe.ingredients << ingredient + + expect(recipe).to be_valid + end + + it "Requires that a name must be present" do + recipe2 = build :recipe, name: nil + + expect(recipe2).to_not be_valid + expect(recipe2.errors.keys).to include(:name) + end + + it "Requires that a preparation must be present" do + recipe = build :recipe, preparation: nil + + expect(recipe).to_not be_valid + expect(recipe.errors.keys).to include(:preparation) + end + end + + describe "alphabet scope" do + # positive test - includes unique formats + + it "has all the unique formats in alphabetical order" do + # We attempted to use Factory Girl, but it wouldn't generate even though we had all the needed attributes for recipe. + + ingredient = Ingredient.create(id: 1, name: "Sumthin") + recipe1 = Recipe.create(name: 'Goulash', ingredient_ids: 1, user_id: 1, preparation: "Stil") + recipe2 = Recipe.create(name: 'Pho', ingredient_ids: 1, user_id: 1, preparation: "Stil") + recipe3 = Recipe.create(name: 'BBQ Chikun', ingredient_ids: 1, user_id: 1, preparation: "Stil") + recipe4 = Recipe.create(name: 'Armadillo', ingredient_ids: 1, user_id: 1, preparation: "Stil") + correct_order = [recipe4, recipe3, recipe1, recipe2] + expect(Recipe.alphabet).to eq correct_order + end + + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb new file mode 100644 index 00000000..2fbde30f --- /dev/null +++ b/spec/models/user_spec.rb @@ -0,0 +1,12 @@ +require 'rails_helper' + +RSpec.describe User, type: :model do + describe "user model validations" do + it "Requires that a name must be present" do + bad_user = build :user, username: nil + + expect(bad_user).to_not be_valid + expect(bad_user.errors.keys).to include(:username) + end + end +end