Chapter 50: Build a Full-Stack App in Ruby
Put it all together: a complete project. In this chapter, you will learn build a full-stack app in depth with Ruby code examples, explanations, and best practices.
Overview
This chapter covers build a full-stack app for Kungfu.js developers using Ruby. We will start with the basics, move through practical examples, and end with advanced techniques and common pitfalls.
Why This Matters
Understanding build a full-stack app is essential because it is a core part of building web applications. Every real-world app needs to handle put it all together: a complete project. Skipping this chapter would leave a gap in your knowledge that would cause problems later.
Code Example
Building a Complete Application
In this final chapter, we will combine everything you have learned into a complete full-stack application. We will build a todo app with:
- Database (SQLite) with CRUD operations
- JWT authentication
- WebSocket for real-time updates
- CSS engine for styling
- SSR with .kng files
- Auto-generated API docs
- Docker deployment
Project Structure
Here is how the complete todo app is organized. Every file is shown below so you can build it yourself without leaving this tutorial:
// app.jsk — complete todo app
const { Kungfu } = require('@kungfu/core');
const { Db } = require('@kungfu/orm');
const db = new Db({ url: 'sqlite://todos.db' });
const app = new Kungfu();
// List all todos
app.get('/api/todos', async (req) => {
const todos = await db.query('SELECT * FROM todos ORDER BY id DESC');
return { status: 200, body: JSON.stringify(todos) };
});
// Create a todo
app.post('/api/todos', async (req) => {
const { title } = JSON.parse(req.body);
const result = await db.execute(
'INSERT INTO todos (title, done) VALUES (?, false)', [title]
);
// Broadcast to all WebSocket clients
app.broadcast('/ws', JSON.stringify({ type: 'created', id: result.lastInsertRowid }));
return { status: 201, body: JSON.stringify({ id: result.lastInsertRowid, title, done: false }) };
});
// Toggle done
app.put('/api/todos/:id/toggle', async (req) => {
await db.execute('UPDATE todos SET done = NOT done WHERE id = ?', [req.params.id]);
return { status: 200, body: '{"ok":true}' };
});
// Delete
app.delete('/api/todos/:id', async (req) => {
await db.execute('DELETE FROM todos WHERE id = ?', [req.params.id]);
return { status: 204, body: '' };
});
// WebSocket for real-time updates
app.ws('/ws', (ws) => {
ws.on('message', (msg) => console.log('client says:', msg));
});
app.listen(3000);
How the Pieces Fit Together
The Rust core handles HTTP parsing, routing, and the WebSocket connection. The Ruby binding registers route handlers that call into the ORM for database operations. The .kng files handle the frontend — data() fetches todos from the API, template() renders them as HTML, and the hydration script makes the page interactive. When a todo is created, the server broadcasts a WebSocket message to all connected clients, and the UI updates in real time without a page refresh.
Running the App
ruby app.rb
# Then open http://localhost:3000 in your browser
Congratulations!
You have completed all 50 chapters of the Kungfu.js tutorial for Ruby. You now know how to build, secure, test, and deploy production-grade web applications with Kungfu.js.
What to do next:
- Build your own project using what you learned
- Share what you built with the community
- Write about your experience with Kungfu.js
- Help others learn by answering questions
Common Mistakes
- Not reading the documentation: Always check the API reference when something does not work as expected.
- Skipping security: Never disable the default middleware unless you have a very good reason. Security is not optional.
- Not testing: Write tests for your handlers. Kungfu.js makes this easy with the built-in test utilities.
Summary
In this chapter, you learned about build a full-stack app in Ruby. You saw code examples, understood how things work under the hood, and learned about common mistakes to avoid.