Last active
December 20, 2024 15:02
-
-
Save hoangsonww/4715b7cb1fd24217cdaa2d38a8001c8a to your computer and use it in GitHub Desktop.
A Ruby on Rails API for a Recipe Sharing Platform that supports user authentication, recipe management, commenting, and admin controls with token-based security.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # frozen_string_literal: true | |
| require 'rails/all' | |
| # Basic Application Setup | |
| class RecipeSharingApp < Rails::Application | |
| config.load_defaults 6.1 | |
| config.api_only = true | |
| end | |
| # Models | |
| class User < ApplicationRecord | |
| has_secure_password | |
| has_many :recipes | |
| has_many :comments | |
| before_create :generate_auth_token | |
| def generate_auth_token | |
| self.auth_token = SecureRandom.hex(10) | |
| end | |
| end | |
| class Recipe < ApplicationRecord | |
| belongs_to :user | |
| has_many :ingredients, dependent: :destroy | |
| has_many :steps, dependent: :destroy | |
| has_many :comments, dependent: :destroy | |
| accepts_nested_attributes_for :ingredients, :steps | |
| end | |
| class Ingredient < ApplicationRecord | |
| belongs_to :recipe | |
| end | |
| class Step < ApplicationRecord | |
| belongs_to :recipe | |
| end | |
| class Comment < ApplicationRecord | |
| belongs_to :recipe | |
| belongs_to :user | |
| end | |
| # Controllers | |
| class ApplicationController < ActionController::API | |
| before_action :authenticate_user | |
| private | |
| def authenticate_user | |
| token = request.headers['Authorization'] | |
| @current_user = User.find_by(auth_token: token) | |
| render json: { error: 'Unauthorized' }, status: :unauthorized if @current_user.nil? | |
| end | |
| def current_user | |
| @current_user | |
| end | |
| end | |
| class UsersController < ApplicationController | |
| skip_before_action :authenticate_user, only: [:create] | |
| def create | |
| user = User.new(user_params) | |
| if user.save | |
| render json: { message: 'User created successfully', token: user.auth_token }, status: :created | |
| else | |
| render json: user.errors, status: :unprocessable_entity | |
| end | |
| end | |
| private | |
| def user_params | |
| params.require(:user).permit(:name, :email, :password, :password_confirmation) | |
| end | |
| end | |
| class SessionsController < ApplicationController | |
| skip_before_action :authenticate_user, only: [:create] | |
| def create | |
| user = User.find_by(email: params[:email]) | |
| if user&.authenticate(params[:password]) | |
| render json: { token: user.auth_token }, status: :ok | |
| else | |
| render json: { error: 'Invalid credentials' }, status: :unauthorized | |
| end | |
| end | |
| end | |
| class RecipesController < ApplicationController | |
| before_action :set_recipe, only: [:show, :update, :destroy] | |
| before_action :authorize_admin, only: [:destroy] | |
| def index | |
| recipes = Recipe.all.includes(:ingredients, :steps) | |
| render json: recipes | |
| end | |
| def create | |
| recipe = current_user.recipes.build(recipe_params) | |
| if recipe.save | |
| render json: recipe, status: :created | |
| else | |
| render json: recipe.errors, status: :unprocessable_entity | |
| end | |
| end | |
| def show | |
| render json: @recipe, include: [:ingredients, :steps, :comments] | |
| end | |
| def update | |
| if @recipe.update(recipe_params) | |
| render json: @recipe | |
| else | |
| render json: @recipe.errors, status: :unprocessable_entity | |
| end | |
| end | |
| def destroy | |
| @recipe.destroy | |
| head :no_content | |
| end | |
| private | |
| def set_recipe | |
| @recipe = Recipe.find(params[:id]) | |
| rescue ActiveRecord::RecordNotFound | |
| render json: { error: 'Recipe not found' }, status: :not_found | |
| end | |
| def recipe_params | |
| params.require(:recipe).permit(:title, :description, ingredients_attributes: [:name, :quantity], steps_attributes: [:description]) | |
| end | |
| def authorize_admin | |
| render json: { error: 'Forbidden' }, status: :forbidden unless current_user&.admin? | |
| end | |
| end | |
| class CommentsController < ApplicationController | |
| def index | |
| recipe = Recipe.find(params[:recipe_id]) | |
| render json: recipe.comments | |
| end | |
| def create | |
| recipe = Recipe.find(params[:recipe_id]) | |
| comment = recipe.comments.build(comment_params.merge(user: current_user)) | |
| if comment.save | |
| render json: comment, status: :created | |
| else | |
| render json: comment.errors, status: :unprocessable_entity | |
| end | |
| end | |
| private | |
| def comment_params | |
| params.require(:comment).permit(:content) | |
| end | |
| end | |
| # Database Migration Setup | |
| ActiveRecord::Schema.define do | |
| create_table :users, force: :cascade do |t| | |
| t.string :name | |
| t.string :email | |
| t.string :password_digest | |
| t.boolean :admin, default: false | |
| t.string :auth_token | |
| t.timestamps | |
| end | |
| create_table :recipes, force: :cascade do |t| | |
| t.string :title | |
| t.text :description | |
| t.references :user, foreign_key: true | |
| t.timestamps | |
| end | |
| create_table :ingredients, force: :cascade do |t| | |
| t.string :name | |
| t.string :quantity | |
| t.references :recipe, foreign_key: true | |
| t.timestamps | |
| end | |
| create_table :steps, force: :cascade do |t| | |
| t.text :description | |
| t.references :recipe, foreign_key: true | |
| t.timestamps | |
| end | |
| create_table :comments, force: :cascade do |t| | |
| t.text :content | |
| t.references :recipe, foreign_key: true | |
| t.references :user, foreign_key: true | |
| t.timestamps | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Rails.application.routes.draw do | |
| # User registration and login routes | |
| post '/register', to: 'users#create' | |
| post '/login', to: 'sessions#create' | |
| # Routes for recipe management | |
| resources :recipes, only: [:index, :create, :show, :update, :destroy] do | |
| resources :comments, only: [:create, :index] # Nested route for comments on recipes | |
| end | |
| # Admin-specific routes | |
| namespace :admin do | |
| resources :recipes, only: [:destroy] # Admin can delete any recipe | |
| end | |
| end |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Recipe Sharing Platform API
This project is a Recipe Sharing Platform built using the Ruby on Rails framework. It provides a backend API that allows users to register and log in, create and manage recipes, add ingredients and steps to each recipe, and comment on recipes. The platform supports role-based access control for admin users to manage content effectively.
Features
Getting Started
Prerequisites
Installation
Clone the repository:
git clone https://github.com/yourusername/recipe-sharing-app.git cd recipe-sharing-appInstall required gems:
Install the required gems by running:
Set up the database:
Run the database migrations to set up the SQLite3 database:
Run the Rails server:
Start the Rails server:
The API will be available at
http://localhost:3000.API Endpoints
User Management
Register a User
POST /register{ "name": "John Doe", "email": "[email protected]", "password": "password123", "password_confirmation": "password123" }201 Created: User created successfully with an authentication token.422 Unprocessable Entity: Validation errors for missing or incorrect parameters.Login a User
POST /login{ "email": "[email protected]", "password": "password123" }200 OK: Returns a JSON object with the user's authentication token.401 Unauthorized: Invalid credentials.Recipe Management
List All Recipes
GET /recipes200 OK: Returns a list of all recipes.Create a New Recipe
POST /recipesAuthorization: Bearer<auth_token>{ "title": "Chocolate Cake", "description": "A delicious chocolate cake recipe.", "ingredients_attributes": [ {"name": "Flour", "quantity": "2 cups"}, {"name": "Cocoa Powder", "quantity": "1 cup"} ], "steps_attributes": [ {"description": "Mix all dry ingredients."}, {"description": "Add wet ingredients and mix well."} ] }201 Created: Recipe created successfully.401 Unauthorized: User is not authenticated.422 Unprocessable Entity: Validation errors.Get a Recipe by ID
GET /recipes/:id200 OK: Returns the recipe details.404 Not Found: Recipe not found.Update a Recipe
PUT /recipes/:idAuthorization: Bearer<auth_token>{ "title": "Updated Chocolate Cake", "description": "An even more delicious chocolate cake recipe." }200 OK: Recipe updated successfully.401 Unauthorized: User is not authenticated.422 Unprocessable Entity: Validation errors.Delete a Recipe (Admin Only)
DELETE /recipes/:idAuthorization: Bearer<auth_token>204 No Content: Recipe deleted successfully.401 Unauthorized: User is not authenticated.403 Forbidden: User is not an admin.404 Not Found: Recipe not found.Comment Management
List All Comments for a Recipe
GET /recipes/:recipe_id/comments200 OK: Returns a list of comments for the recipe.404 Not Found: Recipe not found.Add a Comment to a Recipe
POST /recipes/:recipe_id/commentsAuthorization: Bearer<auth_token>{ "content": "This is a great recipe!" }201 Created: Comment added successfully.401 Unauthorized: User is not authenticated.404 Not Found: Recipe not found.Testing the API
Use tools like Postman or curl to test the endpoints:
Example: Register a New User
Example: Create a New Recipe
Security Considerations
localStorageor cookies with theHttpOnlyflag).bcryptfor secure storage.Contributing
Contributions are welcome! Please follow these steps to contribute:
git checkout -b feature/your-feature).git commit -m 'Add your feature').git push origin feature/your-feature).License
This project is open-source and available under the MIT License.
By following this guide, you should be able to set up and run the Recipe Sharing Platform API using Ruby on Rails. Feel free to extend and modify the code to add more features or improve functionality.