Task on hand: It's dinner time! Create an application that helps users find the most relevant recipes that they can prepare with the ingredients that they have at home.
A fast and lightweight Rails API for searching recipes by ingredients you already have at home.
🌐 Live frontend demo: recipe-time-frontend.onrender.com
💻 Frontend repo: github.com/ibalosh/recipe_time_frontend
This application allows users to search recipes by one or more ingredients (e.g. eggs mushrooms) and get back recipes that contain the most relevant matches. The API ranks results by how many of the searched ingredients match, relative to each recipe’s total ingredients.
Searching for flour water oil will prefer recipes that contain all ingredients compared to total number ingredients in the recipe.
| Recipe | Total Ingredients | Matched Ingredients | Relevance (%) |
|---|---|---|---|
| Gluten-Free Sourdough Starter | 3 | 3 | 100.00 |
| Fried Flour Tortilla Chips | 2 | 2 | 100.00 |
| Chapati (East African Bread) | 6 | 5 | 83.33 |
The data is imported from a large JSON dataset (9,000+ recipes). The database uses a relational schema with pragmatic denormalization in some areas to favor performance, maintainability, and development speed.
recipes: holds core metadata like title, rating, cook/prep time, image URL, short description, and instructionsingredients: stores individual raw strings (e.g."2 eggs","½ cup milk") associated with a recipeauthors,categories,cuisines: normalized for clean associations and potential filtering
Although a more normalized structure could have been used for ingredients (to separate ingredient by name, unit, measurement unit type), this was intentionally avoided for the following reasons:
- 🧠 The source ingredient data is highly variable and inconsistent (e.g.
"2 eggs","1 egg","egg yolks","beaten eggs"), making automatic parsing error-prone - ⏱️ Attempting to extract consistent quantity, unit, and name would have added significant complexity without clear value for this project scope
- 🚀 Instead, raw ingredient text is stored and searched with fuzzy matching (ILIKE) and trigram indexing, which gives good relevance without full normalization
This tradeoff keeps the schema simple, performant, and tailored for full-text ingredient search — rather than structured nutrition breakdown or measurement conversions.
To ensure fast searches (goal: under 200ms on Render), the following is in place:
- PostgreSQL GIN index on
ingredients.raw_text, enabling trigram-accelerated ILIKE queries - 🔥 Measured local speedup: recipe queries improved from 270ms → 80ms after adding the index
- ✅ Test coverage for data models and API endpoints
- ✅ Improved seeds: transforms fields like URLs and enriches records with fields like
short_descriptionandinstructionsto make the frontend experience more engaging - ✅ Basic authentication: added token-based protection to prevent public access to the API