Rails API for a Recipe Sharing Service
Build a JSON API in Rails for a recipe sharing app: people sign up, log in and get a token, post recipes with their ingredients, and rate other people's recipes from 1 to 5. Recipes can be browsed and searched by anyone, but only their author can change or delete them, and each person can rate a recipe only once. Responses include each recipe's average rating, calculated efficiently. You'll learn Rails in API-only mode, ActiveRecord associations and validations, nested records (a recipe with many ingredients), token authentication with JWT, authorization rules, avoiding slow N+1 queries, serializing JSON, and request specs with RSpec.
- Estimate
- ~11.5h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
Rails · ActiveRecord · JWT
Project roadmap
- 01
Create the app and models
~2hCreate an app with rails new --api using PostgreSQL. Generate User (email unique, password digest via has_secure_password), Recipe (user, title, description, servings, minutes), Ingredient (recipe, name, quantity, unit, position) and Rating (user, recipe, score 1 to 5, with a unique index on user plus recipe). Add associations, validations and dependent: :destroy. Seed some data. Done when: the models and seeds work in the Rails console.
- 02
Add token authentication
~2hAdd POST /signup and POST /login returning a JWT (with the jwt gem) signed with a secret from credentials, containing the user id and an expiry. Add an authenticate_user! before_action that reads the Authorization: Bearer header, verifies the token and sets current_user, returning 401 with a JSON error otherwise. Done when: signing up and logging in return a token, and protected routes reject missing or expired tokens.
- 03
Build the recipe endpoints
~2.5hAdd GET /recipes (public, paginated, with ?q= searching titles and ingredient names), GET /recipes/:id, and POST, PATCH and DELETE for logged-in users. Accept ingredients as a nested array with accepts_nested_attributes_for, and use strong parameters. Only the author can update or delete a recipe (return 403 otherwise). Done when: recipes with ingredients can be created and edited only by their authors.
- 04
Add ratings
~1.5hAdd PUT /recipes/:id/rating, which creates or updates the current user's rating (a user can't rate their own recipe). Include each recipe's average rating and rating count in responses, calculated in the query (with a join and AVG, or counter columns updated when ratings change) rather than per recipe. Done when: ratings update the average, and rating twice changes the rating instead of adding another.
- 05
Serialize efficiently
~1.5hShape the JSON with serializers (for example the Alba or Blueprinter gem, or jbuilder): recipes include the author's name, ingredients in order and rating info, never password digests. Use includes to avoid N+1 queries, and confirm with the bullet gem or by counting queries in the log. Return errors in one consistent format. Done when: listing 20 recipes runs a small, fixed number of queries.
- 06
Write request specs
~2hWrite RSpec request specs with factory_bot: sign up and login (valid and invalid), recipe CRUD with nested ingredients, author-only updates and deletes, search, pagination, rating rules and averages, and 401 and 403 responses. Done when: bundle exec rspec passes.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack