From ab6bfa4c20fe53359bbd9d73424b0b12c0ea4f69 Mon Sep 17 00:00:00 2001 From: Matthew Johnson Date: Tue, 1 Aug 2023 08:25:13 -0600 Subject: [PATCH 1/6] add figaro and api keys. --- Gemfile.lock | 3 +++ db/schema.rb | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3f22dad..753265c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -130,6 +130,8 @@ GEM net-smtp (0.3.3) net-protocol nio4r (2.5.9) + nokogiri (1.15.3-arm64-darwin) + racc (~> 1.4) nokogiri (1.15.3-x86_64-darwin) racc (~> 1.4) pg (1.5.3) @@ -216,6 +218,7 @@ GEM zeitwerk (2.6.9) PLATFORMS + arm64-darwin-22 x86_64-darwin-21 x86_64-darwin-22 diff --git a/db/schema.rb b/db/schema.rb index be3d52c..9ac11a2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_07_30_043726) do +ActiveRecord::Schema[7.0].define(version: 2023_07_29_145822) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" From f49812013d8c44bb5fcc2db5720c544371d7d4b9 Mon Sep 17 00:00:00 2001 From: Matthew Johnson Date: Wed, 2 Aug 2023 09:00:34 -0600 Subject: [PATCH 2/6] add first recipe create test. --- spec/requests/api/v1/recipes/update_spec.rb | 146 ++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 spec/requests/api/v1/recipes/update_spec.rb diff --git a/spec/requests/api/v1/recipes/update_spec.rb b/spec/requests/api/v1/recipes/update_spec.rb new file mode 100644 index 0000000..bdc5595 --- /dev/null +++ b/spec/requests/api/v1/recipes/update_spec.rb @@ -0,0 +1,146 @@ +require 'rails_helper' + +describe 'Recipe API' do + let!(:user_1) { User.create!(uid: '123') } + let!(:recipe_1) { Recipe.create!( + name: 'Salad', + instructions: ",1. Eat it!,", + image_url: "www.image.com", + cook_time: 5, + public_status: true, + source_name: "Chef Mike", + source_url: "www.chefmike.com", + user_submitted: true + ) + } + + describe 'PUT api_v1_recipe_path' do + describe 'happy paths' do + it 'can update one recipe' do + id = recipe_1.id + created_recipe = Recipe.last + + recipe_params = { + name: 'Dope Salad', + instructions: ",1. Rinse spinach and lettuce, 2. Get out that dressing give it a shake, 3. Add chickpeas and tomatoes and strawberries, 4. Shake it off yeah yeah shake it off,", + cook_time: 10, + public_status: true, + source_name: "Chef Mateo", + source_url: "www.chefmateo.com", + user_submitted: false + } + + headers = { 'CONTENT_TYPE' => 'application/json' } + put api_v1_recipe_path(recipe_1), headers:, params: JSON.generate(recipe: recipe_params) + + updated_recipe = Recipe.last + + expect(response).to be_successful + + expect(updated_recipe.id).to eq(created_recipe.id) + expect(updated_recipe.public_status).to eq(created_recipe.public_status) + + expect(updated_recipe.name).to_not eq(created_recipe.name) + expect(updated_recipe.name).to eq("Dope Salad") + + expect(updated_recipe.instructions).to_not eq(created_recipe.instructions) + expect(updated_recipe.instructions).to eq(["1. Rinse spinach and lettuce", " 2. Get out that dressing give it a shake", " 3. Add chickpeas and tomatoes and strawberries", " 4. Shake it off yeah yeah shake it off"]) + + expect(updated_recipe.cook_time).to_not eq(created_recipe.cook_time) + expect(updated_recipe.cook_time).to eq(10) + + expect(updated_recipe.source_name).to_not eq(created_recipe.source_name) + expect(updated_recipe.source_name).to eq("Chef Mateo") + + expect(updated_recipe.source_url).to_not eq(created_recipe.source_url) + expect(updated_recipe.source_url).to eq("www.chefmateo.com") + + expect(updated_recipe.user_submitted).to_not eq(created_recipe.user_submitted) + expect(updated_recipe.user_submitted).to be(false) + end + + # it 'can update ingredients and recipe_ingredients during recipe update' do + # recipe_params = { + # name: 'Dope Salad', + # instructions: '1. Rinse spinach and lettuce,2. Get out that dressing give it a shake, 3. Add chickpeas and tomatoes and strawberries, 4. Shake it off yeah yeah shake it off', + # cook_time: 10, + # public_status: true, + # source_name: user_1.uid, + # source_url: api_v1_user_path(user_1), + # user_submitted: true + # } + + # ingredients_params = [ + # { + # name: 'Spinach', + # units: 1.0, + # unit_type: 'cups' + # }, + # { + # name: 'Lettuce', + # units: 1.0, + # unit_type: 'cups' + # }, + # { + # name: 'Vegan Ranch', + # units: 0.5, + # unit_type: 'cups' + # }, + # { + # name: 'Chickpeas', + # units: 0.5, + # unit_type: 'cups' + # }, + # { + # name: 'Cherry Tomatoes', + # units: 0.5, + # unit_type: 'cups' + # }, + # { + # name: 'Strawberries', + # units: 0.25, + # unit_type: 'cups' + # } + # ] + + # headers = { 'CONTENT_TYPE' => 'application/json' } + # post api_v1_recipes_path, headers:, + # params: JSON.generate(recipe: recipe_params, ingredients: ingredients_params) + + # created_recipe = Recipe.last + # first_ingredient = created_recipe.ingredients.first + + # expect(created_recipe.ingredients.count).to eq(6) + + # expect(first_ingredient.name).to eq(ingredients_params.first[:name]) + # expect(first_ingredient.units).to eq(ingredients_params.first[:units]) + # expect(first_ingredient.unit_type).to eq(ingredients_params.first[:unit_type]) + # end + end + + # describe 'sad paths' do + # it 'will not update a recipe without a name' do + # recipe_params = { + # instructions: '1. Rinse spinach and lettuce, 2. Get out that dressing give it a shake, 3. Add chickpeas and tomatoes and strawberries, 4. Shake it off yeah yeah shake it off', + # cook_time: 10, + # public_status: true, + # source_name: user_1.uid, + # source_url: api_v1_user_path(user_1), + # user_submitted: true + # } + + # headers = { 'CONTENT_TYPE' => 'application/json' } + # post api_v1_recipes_path, headers:, params: JSON.generate(recipe: recipe_params) + + # expect(response).to_not be_successful + # expect(response.status).to eq(404) + + # data = JSON.parse(response.body, symbolize_names: true) + + # expect(data[:errors]).to be_a(Array) + # expect(data[:errors].first[:status]).to eq('404') + # expect(data[:errors].first[:title]).to eq("Validation failed: Name can't be blank") + # end + # end + end +end \ No newline at end of file From 5de3af94674729ed3fa4ec4e42b422469827bf20 Mon Sep 17 00:00:00 2001 From: Matthew Johnson Date: Wed, 2 Aug 2023 09:01:01 -0600 Subject: [PATCH 3/6] add recipe#update action. --- app/controllers/api/v1/recipes_controller.rb | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/app/controllers/api/v1/recipes_controller.rb b/app/controllers/api/v1/recipes_controller.rb index babff2c..9561637 100644 --- a/app/controllers/api/v1/recipes_controller.rb +++ b/app/controllers/api/v1/recipes_controller.rb @@ -17,6 +17,26 @@ def create render json: RecipeSerializer.new(created_recipe), status: :created end + def update + # Maybe, add find_recipe callback, so it stops if a recipe does not exists? + # For example, "The Recipe you requested does not exist." + if recipe_params[:api_id].nil? + + # updated_recipe = @recipe.update(recipe_params) + # ^^^ Ultimately would like to refactor to this code, after a find_recipe before_callback + # has been successfully created. For now going with code below: + recipe = Recipe.find(params[:id]).update!(recipe_params) + updated_recipe = Recipe.find(params[:id]) + # require 'pry'; binding.pry + render json: RecipeSerializer.new(updated_recipe), status: :ok + else + # SAD PATH - code to let user know they "You do not have access to update this recipe" + # Maybe this is a front-end problem??? + # render json ErrorSerializer.new(:alert) + end + + end + private def recipe_params @@ -28,4 +48,7 @@ def format_instructions(instruction) add_commas = instruction.prepend(',') + ',' add_commas.gsub(', ', ',') end + + #Potential method for #find_recipe to be used as a callback before the recipes#show and recipes#update + end From c7d6ce9c23dd2e67798f890d51494a82d5cda8fd Mon Sep 17 00:00:00 2001 From: Matthew Johnson Date: Wed, 2 Aug 2023 14:28:57 -0600 Subject: [PATCH 4/6] add functionality for a user to update a recipe and its ingredients. --- app/controllers/api/v1/recipes_controller.rb | 17 +++ spec/requests/api/v1/recipes/update_spec.rb | 144 +++++++++++-------- 2 files changed, 104 insertions(+), 57 deletions(-) diff --git a/app/controllers/api/v1/recipes_controller.rb b/app/controllers/api/v1/recipes_controller.rb index 9561637..44b2593 100644 --- a/app/controllers/api/v1/recipes_controller.rb +++ b/app/controllers/api/v1/recipes_controller.rb @@ -20,6 +20,7 @@ def create def update # Maybe, add find_recipe callback, so it stops if a recipe does not exists? # For example, "The Recipe you requested does not exist." + # require 'pry'; binding.pry if recipe_params[:api_id].nil? # updated_recipe = @recipe.update(recipe_params) @@ -27,6 +28,16 @@ def update # has been successfully created. For now going with code below: recipe = Recipe.find(params[:id]).update!(recipe_params) updated_recipe = Recipe.find(params[:id]) + + updated_ingredients = ingredients_params(params) + # require 'pry'; binding.pry + unless updated_ingredients.nil? + updated_recipe.ingredients.destroy_all + updated_ingredients.each do |updated_ingredient| + updated_recipe.ingredients.create!(updated_ingredient) + end + end + # require 'pry'; binding.pry render json: RecipeSerializer.new(updated_recipe), status: :ok else @@ -44,6 +55,12 @@ def recipe_params :source_url, :user_submitted, :api_id) end + def ingredients_params(params) + params.require(:ingredients).map do |ingredient| + ingredient.permit(:name, :instructions, :units, :unit_type) + end + end + def format_instructions(instruction) add_commas = instruction.prepend(',') + ',' add_commas.gsub(', ', ',') diff --git a/spec/requests/api/v1/recipes/update_spec.rb b/spec/requests/api/v1/recipes/update_spec.rb index bdc5595..e0267a3 100644 --- a/spec/requests/api/v1/recipes/update_spec.rb +++ b/spec/requests/api/v1/recipes/update_spec.rb @@ -59,63 +59,93 @@ expect(updated_recipe.user_submitted).to be(false) end - # it 'can update ingredients and recipe_ingredients during recipe update' do - # recipe_params = { - # name: 'Dope Salad', - # instructions: '1. Rinse spinach and lettuce,2. Get out that dressing give it a shake, 3. Add chickpeas and tomatoes and strawberries, 4. Shake it off yeah yeah shake it off', - # cook_time: 10, - # public_status: true, - # source_name: user_1.uid, - # source_url: api_v1_user_path(user_1), - # user_submitted: true - # } - - # ingredients_params = [ - # { - # name: 'Spinach', - # units: 1.0, - # unit_type: 'cups' - # }, - # { - # name: 'Lettuce', - # units: 1.0, - # unit_type: 'cups' - # }, - # { - # name: 'Vegan Ranch', - # units: 0.5, - # unit_type: 'cups' - # }, - # { - # name: 'Chickpeas', - # units: 0.5, - # unit_type: 'cups' - # }, - # { - # name: 'Cherry Tomatoes', - # units: 0.5, - # unit_type: 'cups' - # }, - # { - # name: 'Strawberries', - # units: 0.25, - # unit_type: 'cups' - # } - # ] - - # headers = { 'CONTENT_TYPE' => 'application/json' } - # post api_v1_recipes_path, headers:, - # params: JSON.generate(recipe: recipe_params, ingredients: ingredients_params) - - # created_recipe = Recipe.last - # first_ingredient = created_recipe.ingredients.first - - # expect(created_recipe.ingredients.count).to eq(6) - - # expect(first_ingredient.name).to eq(ingredients_params.first[:name]) - # expect(first_ingredient.units).to eq(ingredients_params.first[:units]) - # expect(first_ingredient.unit_type).to eq(ingredients_params.first[:unit_type]) - # end + it 'can update ingredients and recipe_ingredients during recipe update' do + recipe_params = { + name: 'Dope Salad', + instructions: '1. Rinse spinach and lettuce,2. Get out that dressing give it a shake, 3. Add chickpeas and tomatoes and strawberries, 4. Shake it off yeah yeah shake it off', + cook_time: 10, + public_status: true, + source_name: "Chef Mike", + source_url: "www.chefmike.com", + user_submitted: true + } + + ingredients_params = [ + { + name: 'Spinach', + units: 1.0, + unit_type: 'cups' + }, + { + name: 'Lettuce', + units: 1.0, + unit_type: 'cups' + }, + { + name: 'Vegan Ranch', + units: 0.5, + unit_type: 'cups' + }, + { + name: 'Chickpeas', + units: 0.5, + unit_type: 'cups' + }, + { + name: 'Cherry Tomatoes', + units: 0.5, + unit_type: 'cups' + }, + { + name: 'Strawberries', + units: 0.25, + unit_type: 'cups' + } + ] + + headers = { 'CONTENT_TYPE' => 'application/json' } + post api_v1_recipes_path, headers:, + params: JSON.generate(recipe: recipe_params, ingredients: ingredients_params) + + created_recipe = Recipe.last + id = created_recipe.id + + update_recipe_params = { + name: 'Dope Salad', + instructions: ",1. Rinse spinach and lettuce, 2. Get out that dressing give it a shake, 3. Add chickpeas and tomatoes and strawberries, 4. Shake it off yeah yeah shake it off,", + cook_time: 10, + public_status: true, + source_name: "Chef Mateo", + source_url: "www.chefmateo.com", + user_submitted: false + } + + update_ingredients_params = [ + { + name: 'Cabbage', + units: 2.0, + unit_type: 'cups' + }, + { + name: 'Tomatoes', + units: 1.0, + unit_type: 'cups' + } + ] + + put api_v1_recipe_path(created_recipe), headers:, params: JSON.generate(recipe: update_recipe_params, ingredients: update_ingredients_params) + + + updated_recipe = Recipe.last + first_ingredient = updated_recipe.ingredients.first + last_ingredient = updated_recipe.ingredients.last + # require 'pry'; binding.pry + expect(updated_recipe.ingredients.count).to eq(2) + + expect(first_ingredient.name).to eq(update_ingredients_params.first[:name]) + # expect(first_ingredient.units).to eq(ingredients_params.first[:units]) + # expect(first_ingredient.unit_type).to eq(ingredients_params.first[:unit_type]) + end end # describe 'sad paths' do From 034af95ecfa143eabf6acb93ba888822457b39b6 Mon Sep 17 00:00:00 2001 From: Matthew Johnson Date: Wed, 2 Aug 2023 14:48:40 -0600 Subject: [PATCH 5/6] refactor recipe#update. --- app/controllers/api/v1/recipes_controller.rb | 4 +-- spec/requests/api/v1/recipes/update_spec.rb | 27 ++++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/app/controllers/api/v1/recipes_controller.rb b/app/controllers/api/v1/recipes_controller.rb index 44b2593..acaa300 100644 --- a/app/controllers/api/v1/recipes_controller.rb +++ b/app/controllers/api/v1/recipes_controller.rb @@ -29,9 +29,9 @@ def update recipe = Recipe.find(params[:id]).update!(recipe_params) updated_recipe = Recipe.find(params[:id]) - updated_ingredients = ingredients_params(params) # require 'pry'; binding.pry - unless updated_ingredients.nil? + if params.has_key?(:ingredients) && !params[:ingredients].empty? + updated_ingredients = ingredients_params(params) updated_recipe.ingredients.destroy_all updated_ingredients.each do |updated_ingredient| updated_recipe.ingredients.create!(updated_ingredient) diff --git a/spec/requests/api/v1/recipes/update_spec.rb b/spec/requests/api/v1/recipes/update_spec.rb index e0267a3..057894f 100644 --- a/spec/requests/api/v1/recipes/update_spec.rb +++ b/spec/requests/api/v1/recipes/update_spec.rb @@ -61,9 +61,9 @@ it 'can update ingredients and recipe_ingredients during recipe update' do recipe_params = { - name: 'Dope Salad', - instructions: '1. Rinse spinach and lettuce,2. Get out that dressing give it a shake, 3. Add chickpeas and tomatoes and strawberries, 4. Shake it off yeah yeah shake it off', - cook_time: 10, + name: 'Salad', + instructions: '1. Rinse spinach and lettuce, 4. Shake it off yeah yeah shake it off', + cook_time: 5, public_status: true, source_name: "Chef Mike", source_url: "www.chefmike.com", @@ -124,12 +124,12 @@ { name: 'Cabbage', units: 2.0, - unit_type: 'cups' + unit_type: 'ounces' }, { name: 'Tomatoes', units: 1.0, - unit_type: 'cups' + unit_type: 'ounces' } ] @@ -139,12 +139,23 @@ updated_recipe = Recipe.last first_ingredient = updated_recipe.ingredients.first last_ingredient = updated_recipe.ingredients.last - # require 'pry'; binding.pry expect(updated_recipe.ingredients.count).to eq(2) + expect(first_ingredient.name).to_not eq(ingredients_params.first[:name]) expect(first_ingredient.name).to eq(update_ingredients_params.first[:name]) - # expect(first_ingredient.units).to eq(ingredients_params.first[:units]) - # expect(first_ingredient.unit_type).to eq(ingredients_params.first[:unit_type]) + expect(first_ingredient.name).to eq("Cabbage") + + expect(first_ingredient.units).to_not eq(ingredients_params.first[:units]) + expect(first_ingredient.units).to eq(update_ingredients_params.first[:units]) + expect(first_ingredient.units).to eq(2.0) + + expect(first_ingredient.unit_type).to_not eq(ingredients_params.first[:unit_type]) + expect(first_ingredient.unit_type).to eq(update_ingredients_params.first[:unit_type]) + expect(first_ingredient.unit_type).to eq('ounces') + + expect(last_ingredient.name).to_not eq(ingredients_params.last[:name]) + expect(last_ingredient.name).to eq(update_ingredients_params.last[:name]) + expect(last_ingredient.name).to eq("Tomatoes") end end From 8398edbb4b003fee66ab6a70cf2c4195055bd307 Mon Sep 17 00:00:00 2001 From: Matthew Johnson Date: Wed, 2 Aug 2023 14:51:44 -0600 Subject: [PATCH 6/6] fix whitespaces. --- app/controllers/api/v1/recipes_controller.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/controllers/api/v1/recipes_controller.rb b/app/controllers/api/v1/recipes_controller.rb index acaa300..94dfaf6 100644 --- a/app/controllers/api/v1/recipes_controller.rb +++ b/app/controllers/api/v1/recipes_controller.rb @@ -29,7 +29,6 @@ def update recipe = Recipe.find(params[:id]).update!(recipe_params) updated_recipe = Recipe.find(params[:id]) - # require 'pry'; binding.pry if params.has_key?(:ingredients) && !params[:ingredients].empty? updated_ingredients = ingredients_params(params) updated_recipe.ingredients.destroy_all @@ -37,15 +36,12 @@ def update updated_recipe.ingredients.create!(updated_ingredient) end end - - # require 'pry'; binding.pry render json: RecipeSerializer.new(updated_recipe), status: :ok else # SAD PATH - code to let user know they "You do not have access to update this recipe" # Maybe this is a front-end problem??? # render json ErrorSerializer.new(:alert) end - end private