A Ruby on Rails application for managing restaurant menus with a JSON import feature. This project was built as an interview assignment demonstrating a robust backend API with proper testing and documentation.
- Features
- System Requirements
- Project Setup
- Data Models
- API Endpoints
- JSON Import Tool
- Running Tests
- Development Approach
The application provides the following features:
-
Level 1: Basic Menu Management
- CRUD operations for Menu and MenuItem objects
- Proper relationship modeling
- Well-tested API endpoints
-
Level 2: Multiple Menus Per Restaurant
- Restaurant model with multiple menus
- Unique MenuItem names across the system
- Menu items can appear on multiple menus with different prices
-
Level 3: JSON Import Tool
- HTTP endpoint for importing restaurant data from JSON files
- Command line tool for imports via rake task
- Comprehensive logging and error handling
- Support for different JSON structures
- Ruby 3.4.x
- Rails 8.0.x
- PostgreSQL 17+
- Node.js 22+ (for React frontend)
- Yarn or npm
-
Clone the repository
git clone https://github.com/fhmurakami/popmenu_project.git cd popmenu_project -
Install dependencies
bundle install yarn install # or npm install -
Set up the database
rails db:create rails db:migrate rails db:seed # optional - seeds the database with sample data -
Start the application
# Start Rails server rails server # or bin/dev
The application will be available at http://localhost:3000
The application has the following data models:
-
Restaurant
- Has many Menus
- Attributes: name, address, phone, website, description.
-
Menu
- Belongs to a Restaurant
- Has many MenuItems through MenuEntries
- Attributes: name.
-
MenuItem
- Has many Menus through MenuEntries
- Attributes: name.
-
MenuEntry (Join model)
- Belongs to a Menu
- Belongs to a MenuItem
- Attributes: price, description, category, dietary restrictions, ingredients.
Restaurant ──┐
│
│ has_many
│
▼
Menu ◄────┐
│ │
│ has_many │
│ │
▼ │
MenuEntry │
│ │
│ belongs_to
│ │
▼ │
MenuItem ────┘
GET /api/v1/restaurants- List all restaurantsGET /api/v1/restaurants/:id- Get a specific restaurantPOST /api/v1/restaurants- Create a new restaurantPUT /api/v1/restaurants/:id- Update a restaurantDELETE /api/v1/restaurants/:id- Delete a restaurant
GET /api/v1/restaurants/:restaurant_id/menus- List all menus for a restaurantGET /api/v1/restaurants/:restaurant_id/menus/:id- Get a specific menuPOST /api/v1/restaurants/:restaurant_id/menus- Create a new menuPUT /api/v1/restaurants/:restaurant_id/menus/:id- Update a menuDELETE /api/v1/restaurants/:restaurant_id/menus/:id- Delete a menu
GET /api/v1/menu_items- List all menu itemsGET /api/v1/menu_items/:id- Get a specific menu itemPOST /api/v1/menu_items- Create a new menu itemPUT /api/v1/menu_items/:id- Update a menu itemDELETE /api/v1/menu_items/:id- Delete a menu item
GET /api/v1/menus/:menu_id/menu_items- List all menu items for a menu
POST /api/v1/restaurant_imports- Import restaurant data from a JSON file
The application features a tool for importing restaurant data from JSON files.
{
"restaurants": [
{
"name": "Restaurant Name",
"menus": [
{
"name": "Menu Name",
"menu_items": [
{ "name": "Item Name", "price": 9.0 },
{ "name": "Another Item", "price": 5.0 }
]
}
]
}
]
}The tool also supports dishes instead of menu_items for flexibility.
You can upload a JSON file via the API:
curl -X POST \
-H "Content-Type: multipart/form-data" \
-F "file=@path/to/restaurant_data.json" \
http://localhost:3000/api/v1/restaurant_importsThe response will include success status and detailed logs for each imported item.
You can also import using a rake task:
rake import:restaurants[path/to/restaurant_data.json]This will display logs in the console and set the exit code based on success/failure.
The import process:
- Parses the JSON file
- Creates or finds restaurants by name
- For each restaurant, creates or finds menus by name
- For each menu, processes menu items:
- Finds or creates menu items by name (ensuring uniqueness)
- Creates menu entries with the appropriate prices
- Logs each step and any errors
- Returns a comprehensive report
The project has comprehensive test coverage using RSpec:
# Run all tests
bundle exec rspec
# Run specific test files
bundle exec rspec spec/models/restaurant_spec.rb
bundle exec rspec spec/services/restaurant_import_service_spec.rbThis project was developed following an iterative approach, tackling one level at a time as per the requirements. Each level was completed with proper testing before moving on to the next.
- Service Object Pattern - Used for complex operations like the JSON import process
- Comprehensive Logging - Detailed logging for import operations
- Error Handling - Robust error handling for API endpoints and import operations
- Transaction Support - Database transactions to ensure data integrity
- Test-Driven Development - Extensive test coverage for all features
- Menu item names are globally unique across the system
- The same menu item can have different prices on different menus
- Import operations should be idempotent (can be run multiple times with the same data)
- JSON format might have variations (like "dishes" vs "menu_items") that should be handled gracefully