A client web app for the Recipe Puppy API.
Queries the API for the given search term, displaying the first 20 results found with complete data (in particular: including a thumbnail image url).
- VCR and WebMock for stubbing out API calls.
- Capybara and Poltergeist for BDD and headless UI testing
- RSpec for testing
- HTTParty for API calls
- Ruby Babel to make ES2015 available via the asset pipeline
# config/routes.rb L4-L5 (37302a48)
resources :recipes, only: %i(index)
root to: "static_pages#home"
config/routes.rb#L4-L5 (37302a48)
# app/controllers/recipes_controller.rb L4-L11 (37302a48)
def index
recipes = RecipePuppy
.query_for_n_entries(n: 20,
query: params[:query],
ingredients: params[:ingredients])
render :index, locals: { recipes: recipes }, layout: false
end
app/controllers/recipes_controller.rb#L4-L11 (37302a48)
# app/models/recipe_puppy.rb L3-L5 (37302a48)
class RecipePuppy
include HTTParty
base_uri "http://www.recipepuppy.com/api"
app/models/recipe_puppy.rb#L3-L5 (37302a48)
# app/models/recipe_puppy_recipe.rb L3-L17 (888583e0)
class RecipePuppyRecipe
DEFAULT_THUMBNAIL_URL = "http://img.recipepuppy.com/9.jpg"
attr_accessor :ingredients_list, :url, :title, :thumbnail_url
def self.new_collection(attrs_list)
attrs_list.map { |attrs| new(attrs.with_indifferent_access) }
end
def initialize(attrs)
self.ingredients_list = (attrs[:ingredients] || "").split(/,\s?/).uniq
self.url = attrs[:href]
self.thumbnail_url = attrs[:thumbnail].presence || DEFAULT_THUMBNAIL_URL
self.title = attrs[:title]
end
app/models/recipe_puppy_recipe.rb#L3-L17 (888583e0)
Client-side code listens for form submissions and for click events emitted from ingredient links:
// app/assets/javascripts/recipe_search.js.es6 L7-L24 (37302a48)
$(() => {
const $form = $(".js-search-form").first()
const $resultsContainer = $(".js-search-results").first()
$form.on("submit", (event) => {
event.preventDefault()
const queryParams = $(event.target).serialize()
queryForRecipes(queryParams, $resultsContainer)
})
$resultsContainer.on("click", ".js-search-link", (event) => {
event.preventDefault()
const searchTerm = $(event.target).text()
$form.find("input").val(searchTerm)
$(document).scrollTop(0)
queryForRecipes(`ingredients=${searchTerm}`, $resultsContainer)
})
})
app/assets/javascripts/recipe_search.js.es6#L7-L24 (37302a48)