This tutorial will guide you through building a basic web application that demonstrates communication between a Next.js frontend and a Ruby on Rails API backend. This is perfect for beginners to understand how modern web applications handle frontend-backend communication.
Prerequisites
- Basic knowledge of JavaScript/React
- Basic understanding of Ruby on Rails
- Node.js and npm installed
- Ruby and Rails installed
- A code editor (VS Code recommended)
Project Structure
simple_app/
├── simple-app-frontend/ (Next.js)
└── simple-app-backend/ (Rails API)
Part 1: Setting Up the Backend (Rails API)
Create a new Rails API:
rails new simple-app-backend --api cd simple-app-backend
Add CORS to your Gemfile:
gem 'rack-cors'
Install dependencies:
bundle install
Configure CORS in config/initializers/cors.rb:
Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins 'http://localhost:3000' resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head] end end
Generate the API controller:
rails generate controller api/v1/Data index
Create a simple endpoint (app/controllers/api/v1/data_controller.rb):
class Api::V1::DataController < ApplicationController def index render json: { message: "Hello from Rails API!" } end end
Set up routes in config/routes.rb:
Rails.application.routes.draw do namespace :api do namespace :v1 do get 'data', to: 'data#index' end end end
Part 2: Setting Up the Frontend (Next.js)
If you haven’t installed Next.js yet, you can follow this guide: How to Install Next.js.
Create a Next.js application:
npx create-next-app@latest simple-app-frontend
Answer the prompts:
- Would you like to use TypeScript? → No
- Would you like to use ESLint? → Yes
- Would you like to use Tailwind CSS? → Yes
- Would you like to use src/ directory? → Yes
- Would you like to use App Router? → Yes
- Would you like to use Turbopack? → No
- Would you like to customize the default import alias? → No
Go to the frontend directory:
cd simple-app-frontend
Update src/app/page.js:
'use client'; import { useState, useEffect } from 'react'; export default function Home() { const [message, setMessage] = useState('Loading...'); useEffect(() => { const fetchData = async () => { try { const response = await fetch('http://localhost:3001/api/v1/data'); const data = await response.json(); setMessage(data.message); } catch (error) { console.error('Error:', error); setMessage('Error loading data'); } }; fetchData(); }, []); return ( <main className="flex min-h-screen flex-col items-center p-24"> <div className="text-center"> <h1 className="text-4xl font-bold mb-4">Simple App</h1> <p className="text-xl">{message}</p> </div> </main> ); }
Part 3: Running Your Application
Start the Rails server:
# In simple-app-backend directory rails server -p 3001
Start the Next.js development server:
# In simple-app-frontend directory npm run dev
Visit http://localhost:3000 in your browser to see your app in action.
Understanding How It Works
Frontend (Next.js)
- Page Load:
- Shows initial "Loading..." state
- Runs useEffect hook after mounting
- Makes API request to Rails backend
- Component Structure:
- 'use client' enables client-side features
- useState manages message state
- useEffect handles API communication
Backend (Rails)
- Request Handling:
- Receives request at /api/v1/data
- Returns JSON response
- CORS allows frontend access
Communication Flow
Browser (localhost:3000) ↓ Next.js Frontend ↓ Rails API (localhost:3001) ↓ JSON Response ↓ Update UI
Common Issues and Solutions
- CORS Errors:
- Check CORS configuration in Rails
- Verify frontend URL in CORS settings
- Ensure Rails server is running on port 3001
- Connection Issues:
- Confirm both servers are running
- Check port numbers
- Verify API endpoint URL