Skip to content
Ruby on Rails

A tutorial on how to built a headless CMS with Ruby on Rails

Table of Contents

  1. Introduction
    1.1 Overview of Book Bazaar
    1.2 The Role of Headless CMS in Modern Development
    1.3 Why Ruby on Rails?
    1.4 Relevance to ICT Trends and Professional Profiles

  2. Installation
    2.1 Prerequisites
    2.2 Setting Up the Project
    2.3 Configuring Docker (Optional)

  3. Configuration
    3.1 Database Configuration
    3.2 Adding Gems to Enhance Functionality
    3.3 Setting Up Application Structure

  4. Basic Functionality
    4.1 Creating Models and Migrations
    4.2 Setting Up Controllers and Routes
    4.3 Building API Endpoints
    4.4 Testing APIs with Postman and curl

  5. Advanced Functionalities
    5.1 Implementing Pagination with Kaminari
    5.2 Adding SEO with FriendlyId
    5.3 Filtering and Sorting Products
    5.4 Tracking Popular Items

  6. Images, Diagrams, and Code Snippets
    6.1 Screenshots of the Setup Process
    6.2 Entity-Relationship Diagram (ERD)
    6.3 API Request-Response Lifecycle Diagram

  7. Best Practices
    7.1 Following Rails Conventions
    7.2 Securing APIs with JWT
    7.3 Validating Inputs and Preventing Invalid Data
    7.4 Optimizing Queries

  8. Future Updates and Versions
    8.1 Features to Expand Book Bazaar
    8.2 New Features in Upcoming Rails Versions

  9. Conclusion

  10. References

Introduction

Overview of Book Bazaar

Book Bazaar is a simplified headless CMS, inspired by platforms like Shopify, that focuses on flexibility and scalability. It allows developers to manage and serve content independently of the frontend, making it ideal for modern applications that require API-first architecture. The backend is built with Ruby on Rails, leveraging its robust framework to deliver clean, maintainable, and performant code. By the end of this tutorial, you’ll have a functional CMS backend capable of handling products, categories, and orders, with advanced features like pagination, filtering, and SEO.

The Role of Headless CMS in Modern Development

Traditional CMS platforms often tie the backend directly to the frontend, limiting flexibility in delivering content to multiple platforms. A headless CMS decouples the two, allowing the backend to serve data via APIs that can be consumed by websites, mobile apps, or even IoT devices. This approach is becoming increasingly popular due to its ability to provide omnichannel experiences, faster load times, and developer-friendly APIs. Book Bazaar embraces this modern approach, enabling seamless integration with diverse frontends while ensuring scalability and performance.

Why Ruby on Rails?

Ruby on Rails is a proven web development framework known for its productivity and convention-over-configuration philosophy. It includes powerful tools for database management, routing, and API creation out of the box, which makes it a natural choice for building a headless CMS like Book Bazaar. Features such as Active Record, RESTful architecture, and the availability of a rich ecosystem of gems allow developers to rapidly prototype and deploy applications. Rails also emphasizes clean, maintainable code, which is essential for long-term project sustainability.

Headless CMS solutions align with current ICT trends such as API-first development, cloud-based services, and modular application design. They cater to the growing need for scalable and versatile content delivery systems. For developers, mastering this approach expands opportunities across various career profiles:

  • Full-Stack JavaScript Developers can create dynamic frontends to consume the APIs.
  • Front-End Developers can focus solely on the UI/UX without backend constraints.
  • Back-End Developers can explore efficient API design and architecture.
  • CMS Themers can integrate Book Bazaar with various platforms to provide customized solutions.

By building Book Bazaar, you gain hands-on experience in addressing real-world challenges, keeping you competitive in the rapidly evolving tech landscape.

Installation

Prerequisites

Before starting, ensure that your development environment is properly set up. Below are the tools and software you will need:

  1. Ruby: Install the latest version of Ruby. You can check if Ruby is installed by running:
    bash
    ruby -v

If not installed, download it from (https://www.ruby-lang.org/en/downloads/).

  1. Ruby on Rails: Install Rails using the following command:

    bash
    gem install rails

    Confirm the installation by running:

    bash
     rails -v
  2. MySQL: Book Bazaar uses MySQL as the database. Install MySQL by following the instructions on the official website: https://dev.mysql.com/doc/.

  3. VSCode: Use VSCode for coding. Download it from https://code.visualstudio.com/.

  4. Optional: Docker: For containerizing the database, install Docker. Download it from https://www.docker.com/.

Setting Up the Project

  1. Create a New Rails Application: Run the following command in your integrated terminal to create a new Rails application named book_bazaar:

    bash
    rails new book_bazaar --api -d mysql
  2. Navigate to the Project Directory: Move into the newly created project directory:

    bash
    cd book_bazaar
  3. Start the Rails Server: Launch the Rails server to ensure the application is running correctly:

    bash
    rails s
  4. Access the Application: Open your browser and visit http://localhost:3000. You should see the Rails welcome page, indicating that the setup was successful.

  5. Stop the Server: Press Ctrl + C in the terminal to stop the Rails server.

Configuring Docker (Optional)

If you prefer to use Docker for database management, follow these steps:

  1. Create a docker-compose.yml File: Create a new file named docker-compose.yml in the project root directory and add the following configuration:

    yaml
    version: '3.8'
    services:
      db:
        image: mysql:5.7
        restart: always
        environment:
          MYSQL_ROOT_PASSWORD: password
          MYSQL_DATABASE: book_bazaar_development
          MYSQL_USER: root
          MYSQL_PASSWORD: password
        ports:
          - "3306:3306"
  2. Start the Docker Container: Run the following command to start the MySQL container:

    bash
     docker-compose up -d
  3. Update config/database.yml: Modify the config/database.yml file to use the Docker container for the database connection. Update the development section as follows:

    yaml
    development:
      adapter: mysql2
      encoding: utf8
      database: book_bazaar_development
      pool: 5
      username: root
      password: password
      host: db
  4. Create the Database: Run the following command to create the database:

    bash
    rails db:create
  5. Testing setup: Verify the rails server is running by starting it with rails s and accessing http://localhost:3000 in your browser. If using Docker, ensure the MySQL container is running by checking docker ps in your terminal.

  6. Test database connection: Confirm the database connection by running rails db:migrat:status to create the necessary tables.

Configuration

3.1 Database Configuration

To connect your Rails application to a MySQL database, update the config/database.yml file. Replace the default settings with your MySQL database credentials:

yaml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: your_database_username
  password: your_database_password
  host: localhost

development:
  <<: *default
  database: book_bazaar_development

test:
  <<: *default
  database: book_bazaar_test

production:
  <<: *default
  database: book_bazaar_production
  username: <%= ENV['DATABASE_USERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>

Save the file and create the database by running rails db:create. This will create book_bazaar_development, book_bazaar_test, and book_bazaar_production databases.

3.2 Adding Gems to Enhance Functionality

Ruby on Rails has a vibrant ecosystem of gems that can add powerful features to your application. In this tutorial, we’ll use the following gems:

  • Kaminari: For pagination
  • FriendlyId: For SEO-friendly URLs Add these gems to your Gemfile:
ruby
gem 'kaminari'
gem 'friendly_id'

After adding the gems, install them by running:

bash
bundle install

Once installed, configure the gems as needed:

  1. Generate the Kaminari views (optional):
    bash
      rails g kaminari:views bootstrap4
  2. Generate a migration for FriendlyId:
    bash
      rails generate friendly_id
      rials db:migrate

3.3 Setting Up Application Structure

To organize the application, create the necessary models, controllers, and routes. Here’s a basic structure to get you started:

  1. Models: Create models for products, categories, and orders. Use the following commands to generate the models:
    bash
    rails g model Product name:string price:decimal category:references
    rails g model Category name:string
    rails g model Order total:decimal
  2. Controllers: Generate controllers for products, categories, and orders:
    bash
    rails g controller Products
    rails g controller Categories
    rails g controller Orders
  3. Routes: Define routes for the API endpoints in config/routes.rb:
    ruby
    namespace :api do
      namespace :v1 do
        resources :products
        resources :categories
        resources :orders
      end
    end
  4. Migrations: Run the migrations to create the necessary tables in the database:
    bash
    rails db:migrate
  5. Seed Data: Optionally, add seed data to populate the database with sample records:
    ruby
    # db/seeds.rb
    Category.create(name: 'Fiction')
    Category.create(name: 'Non-Fiction')
    Product.create(name: 'Book 1', price: 10.99, category_id: 1)
    Product.create(name: 'Book 2', price: 15.99, category_id: 2)
    Order.create(total: 26.98)

Run rails db:seed to populate the database with the seed data.

Basic Functionality

4.1 Creating Models and Migrations

In this section, we’ll create the foundational models for our Book Bazaar CMS. We need models for the main entities in the system, such as Product, Category, and Order. First, we’ll define the database schema by creating migrations for these models.

To create a Product model, use the following command:

bash
rails g model Product name:string description:text price:decimal stock:integer
rails db:migrate

Next, generate a Category model:

bash
rails g model Category name:string
rails db:migrate

Finally, create an Order model:

bash
rails g model Order total:decimal
rails db:migrate

4.2 Setting Up Controllers and Routes

Once the models are in place, we need to create controllers to handle incoming API requests and perform actions on the models. Rails makes this process simple with its scaffold generators.

Generate a scaffold for the Product controller:

bash
rails g controller Api::Products

This will generate the controller with basic CRUD actions (index, show, create, update, destroy). Open the generated controller in app/controllers/api/products_controller.rb and implement these actions:

ruby
class Api::ProductsController < ApplicationController
  def index
    products = Product.all
    render json: products
  end

  def show
    product = Product.find(params[:id])
    render json: product
  end

  def create
    product = Product.new(product_params)
    if product.save
      render json: product, status: :created
    else
      render json: product.errors, status: :unprocessable_entity
    end
  end

  def update
    product = Product.find(params[:id])
    if product.update(product_params)
      render json: product
    else
      render json: product.errors, status: :unprocessable_entity
    end
  end

  def destroy
    product = Product.find(params[:id])
    product.destroy
    head :no_content
  end

  private

  def product_params
    params.require(:product).permit(:name, :description, :price, :stock)
  end
end

Repeat the same process for the Category and Order controllers. Define the necessary actions to handle CRUD operations on these resources. Now, update the config/routes.rb file to create API routes for products:

ruby
namespace :api do
  namespace :v1 do
    resources :products
    resources :categories
    resources :orders
  end
end

This defines the necessary routes for interacting with the Product resource via the API.

4.3 Building API Endpoints

With the models and controllers set up, we now have to ensure our API endpoints are working correctly. Using Rails, the index action will return all products, the show action will return a single product, and so on.

To test the API endpoints, start the Rails server by running rails s and use a tool like Postman to send requests to the API. For example, to get all products, send a GET request to http://localhost:3000/api/v1/products.

bash
curl http://localhost:3000/api/v1/products

You should receive a JSON response containing all the products in the database.

bash
curl http://localhost:3000/api/products/1

This will return the details of the product with ID 1.

4.4 Testing APIs with Postman and curl

For thorough testing, Postman is an excellent tool for sending requests to your API and inspecting responses. You can use it to test all CRUD operations for products, including creating, updating, and deleting products.

Alternatively, you can use curl commands in the terminal to interact with the API. For example, to create a new product, you can send a POST request using curl:

bash
curl -X POST -H "Content-Type: application/json" -d '{"name": "Book 3", "price": 19.99, "stock": 100}' http://localhost:3000/api/v1/products

This will create a new product with the specified details. Using curl for testing is straightforward:

  • -X specifies the HTTP method (GET, POST, PUT, DELETE).
  • -H sets the request header.
  • -d sends data in the request body.

To update a product:

bash
curl -X PUT -H "Content-Type: application/json" -d '{"price": 24.99}' http://localhost:3000/api/v1/products/1

To delete a product:

bash
curl -X DELETE http://localhost:3000/api/v1/products/1

By testing these API endpoints, you can ensure that your Book Bazaar CMS is functioning as expected.

Advanced Functionalities

5.1 Implementing Pagination with Kaminari

Pagination is an essential feature for handling large datasets efficiently. In this section, we'll integrate the Kaminari gem to paginate the product listings in our API. This allows users to view products in chunks, improving performance and user experience.

To get started, first install the Kaminari gem by adding it to your Gemfile:

ruby
gem 'kaminari'

Run bundle install to install the gem. Then, modify the controller to paginate the products:

ruby
class Api::ProductsController < ApplicationController
  def index
    products = Product.page(params[:page]).per(params[:per_page])
    render json: products
  end
end

This will return a paginated list of products, 10 per page. You can adjust the number per page based on your needs. To access different pages, provide a page query parameter, like /api/products?page=2.

5.2 Adding SEO with FriendlyId

SEO optimization is key for improving the visibility of your content. In this section, we’ll use the FriendlyId gem to generate human-readable slugs for our products, enhancing their SEO-friendliness.

Start by adding the gem to your Gemfile:

ruby
gem 'friendly_id'

Run bundle install to install the gem. Next, generate a migration to add a slug column to the products table:

bash
rails generate migration add_slug_to_products slug:string:uniq
rails db:migrate

Update the Product model to include the FriendlyId module:

ruby
class Product < ApplicationRecord
  extend FriendlyId
  friendly_id :name, use: :slugged
end

This configuration generates a URL-friendly slug based on the product name, allowing for cleaner, more SEO-friendly URLs like /products/awesome-book.

5.3 Filtering and Sorting Products

Providing users with filtering and sorting options is crucial for improving the user experience, especially in large product catalogs. In this section, we’ll implement basic filtering by category and price range, as well as sorting by popularity.

To filter products by category, update the index action in the Products controller:

ruby
class Api::ProductsController < ApplicationController
  def index
    products = Product.all
    products = products.where(category_id: params[:category_id]) if params[:category_id].present?
    products = products.where('price >= ?', params[:min_price]) if params[:min_price].present?
    products = products.where('price <= ?', params[:max_price]) if params[:max_price].present?
    render json: products
  end
end

This allows users to filter products by category ID and price range. To sort products by popularity, you can track the number of views for each product and order the products based on this metric.

To keep track of product popularity, we can implement a basic view counter. This feature will allow us to increment the view count every time a product is accessed, which can be useful for highlighting popular items. First, add a views column to the products table:

bash
rails generate migration add_views_to_products views:integer
rails db:migrate

Next, modify the show action to increment the view count:

ruby
class Api::ProductsController < ApplicationController
  def show
    product = Product.find(params[:id])
    product.increment!(:views)
    render json: product
  end
end

This will increment the view count every time a product is accessed. You can then sort products based on the view count to display popular items.

Images, Diagrams, and Code Snippets

6.1 Screenshots of the Setup Process

6.2 Entity-Relationship Diagram (ERD)

Example ERD:

+–––––––+ +——————+ +————+ | Product | | Category | | Order | +–––––––+ +——————+ +————+ | id | | id | | id | | name | | name | | product_id | | description | | description | | quantity | | price | +——————+ | total_price| | stock | | created_at | +–––––––+ +————+ | | +—————————————————–+

Foreign Key: product_id: references Product(id)

6.3 API Request-Response Lifecycle Diagram

API Request-Response Lifecycle: Client Request -> API Controller -> Model/Database Query -> Response -> Client.

Best Practices

7.1 Following Rails Conventions

  • Conventions over Configuration: Rails is built around a philosophy of "convention over configuration." Following Rails conventions ensures that your application stays aligned with the expectations of the Rails community. For example, the names of your controllers, models, and views should follow specific conventions to reduce the need for additional configuration. Adhering to this principle will make your code easier for others to read, and will allow Rails to handle common tasks, such as URL routing and file management, automatically.

  • RESTful Routes: REST (Representational State Transfer) is an architectural style that ensures your API endpoints are predictable and easy to use. In Rails, RESTful routing is a default, and it's important to follow this pattern for your resources. This structure promotes a clear separation between different types of requests (GET, POST, PUT, DELETE) and their corresponding actions (index, show, create, update, destroy), making the API easier to understand and maintain. For example, when designing API routes for a Product resource, you would use /products for the index and /products/:id for showing a single product.

  • ActiveRecord: Rails’ ActiveRecord is a powerful ORM (Object-Relational Mapping) system that allows you to interact with your database using Ruby code rather than SQL queries. It abstracts away the complexity of SQL, provides a cleaner interface, and reduces the chance of SQL injection attacks. By relying on ActiveRecord for querying, you can write more maintainable code and use built-in methods like .find, .create, .update, and .destroy to perform database operations safely and efficiently.

7.2 Securing APIs with JWT

  • JWT Authentication: JSON Web Tokens (JWT) are a compact, URL-safe method for representing claims to be transferred between two parties. In the context of a headless CMS, JWT is commonly used for securing API endpoints. After a user logs in with valid credentials, the server generates a JWT that contains the user’s identity and permissions. This token is sent to the client, which uses it to authenticate subsequent API requests. JWT is stateless, meaning that the server does not store any session data, improving scalability.

  • Token Expiry and Refresh: Always set an expiration time for your JWTs to limit the time window during which a token can be used. This helps mitigate the risks associated with token theft. You can implement short-lived access tokens and long-lived refresh tokens. The access token expires quickly (e.g., in 15 minutes), while the refresh token allows the user to obtain a new access token without requiring them to log in again. This provides a balance between user convenience and security.

  • Role-Based Access Control: Utilize the claims stored in the JWT to implement Role-Based Access Control (RBAC). RBAC allows you to assign different roles (e.g., admin, user, guest) to your users and restrict access to resources based on their role. For example, an admin user might have the ability to create, update, and delete products, while a guest might only have access to read-only endpoints. Using the JWT claims to manage permissions helps maintain a secure and flexible access control model.

7.3 Validating Inputs and Preventing Invalid Data

  • Model Validations: In Rails, model validations ensure that only valid data is saved to the database. For example, you can use validates_presence_of to ensure required fields are not empty, validates_numericality_of to ensure a field contains only numbers, and validates_uniqueness_of to prevent duplicate entries. These validations are crucial for data integrity and help catch issues early. For a headless CMS, this might include validating fields like product names, prices, or categories before they’re persisted.

  • Strong Parameters: Rails' strong parameters system is used to filter and permit only the attributes that should be allowed to be modified by the user. This prevents unwanted attributes from being accidentally or maliciously modified. For example, when creating or updating a Product, you might permit only certain fields like name, description, and price. By using params.require(:product).permit(:name, :description, :price), you ensure that only these attributes are used in the controller action, reducing the risk of mass-assignment vulnerabilities.

  • Error Handling: Proper error handling is essential to providing a good API experience. When a user submits invalid data or an operation fails, returning a clear and helpful error message allows the consumer of your API to understand what went wrong. In Rails, this can be done by using the errors method on models and returning appropriate HTTP status codes (e.g., 400 for bad requests, 422 for unprocessable entity). For example, if a user tries to submit a product without a name, the response might include {"error": "Product name can't be blank"}.

7.4 Optimizing Queries

  • Avoid N+1 Queries: N+1 queries occur when your application queries the database in a loop, resulting in a separate query being executed for each item in a collection. This can severely impact performance, especially for large datasets. To prevent N+1 queries, you should use includes or joins to eager load related models in a single query. For example, if you have a Product model that belongs to a Category, instead of loading each category separately with Product.all.each { |product| product.category }, you can use Product.includes(:category).all to fetch both products and categories in a single query.

  • Indexes: Database indexes improve the speed of data retrieval operations by allowing the database to find rows more efficiently. Indexes are particularly important on columns that are frequently used in WHERE clauses, joins, or ordering. For example, if you often query products by category_id, you should add an index on the category_id column in the products table. This will speed up queries and reduce the load on the database.

  • Database Transactions: Use database transactions to ensure that your database operations are atomic. A transaction ensures that all changes are committed together or none at all. This is important when performing multiple related database operations, such as creating an order with multiple items. If an error occurs during any of the operations, the transaction is rolled back, and no data is written to the database. In Rails, you can use ActiveRecord::Base.transaction to wrap a block of code in a transaction.

Future Updates and Versions

8.1 Features to Expand Book Bazaar

As you continue to develop Book Bazaar, several key features can be added to enhance its functionality, scalability, and overall user experience:

  • Third-Party API Integration: To extend the capabilities of your CMS, integrating third-party APIs is essential. Payment gateways like Stripe or PayPal can facilitate secure online transactions, while shipping APIs (e.g., Shippo or UPS) can automatically calculate shipping rates and provide tracking information. This will streamline order processing and improve the customer experience.

  • GraphQL Support: Adding GraphQL support to your CMS can offer more flexibility compared to REST APIs. GraphQL allows clients to query exactly the data they need, improving performance by reducing unnecessary data transfers. This is especially useful in CMS applications where frontend clients often need to fetch a variety of data, such as product details, categories, and reviews.

  • Admin Dashboard: A feature-rich admin panel would greatly improve the ease of content management. Implementing an admin dashboard would allow non-technical users to manage products, view orders, track inventory, and handle user management without needing to interact directly with the database. Using gems like ActiveAdmin or RailsAdmin, you can quickly add a customizable, user-friendly interface.

  • User Authentication and Authorization: Adding user authentication (using gems like Devise) and role-based access control is crucial for any CMS where different users may have different levels of access. For instance, you could allow admins to manage all aspects of the CMS, while giving editors access to only content management, and customers access to their own orders. This will enhance security and improve the user experience.

  • Product Variants: Many e-commerce platforms require support for product variants (e.g., different sizes, colors, and materials). By implementing this feature, you can allow customers to choose from various options of a product, each with its own unique pricing and inventory status. This could be achieved by extending the Product model to include associations for variants and attributes.

  • Real-Time Features: With the addition of WebSockets or ActionCable, you can introduce real-time features into Book Bazaar. For example, you could notify users of live updates, such as stock availability or the status of their orders. Real-time capabilities would create a more dynamic and interactive experience for users, which is especially useful in fast-paced environments like e-commerce.

8.2 New Features in Upcoming Rails Versions

Ruby on Rails is actively evolving, and keeping up with its updates can help you improve Book Bazaar's performance, security, and maintainability. Here are some anticipated changes that could benefit the platform:

  • Rails 8 (or Later Versions): With the release of Rails 8 (or later versions), there may be improvements in API mode and updates that streamline the process of building API-only applications. Additionally, updates to default configurations and optimizations for database connections will likely enhance performance, making it easier to scale Book Bazaar as the user base grows. Keeping up with these updates will ensure that the application remains modern and efficient.

  • Active Record Enhancements: In future versions of Rails, expect continued enhancements to Active Record, particularly around handling complex queries, database joins, and large datasets. With features like materialized views and window functions, handling high-traffic databases and large catalogs of products will become much more efficient, leading to improved performance in querying product data, customer records, and transactions.

  • Improved Background Jobs: Background jobs are essential for tasks that are time-consuming or resource-intensive, such as sending order confirmation emails or processing payments. Future versions of Rails may provide more advanced features for background job processing, such as better integration with Sidekiq or improvements to ActiveJob that can help process jobs more efficiently. This would result in faster processing times and less strain on the main application server.

  • Better Webpacker/Importmap Integration: The management of front-end assets is an ever-evolving space in Rails. With updates to Webpacker and Importmap, developers will likely experience better handling of JavaScript and CSS. For instance, Webpacker may become even more intuitive with bundling assets and integrating frameworks like React or Vue.js. For simpler projects, Importmap may make asset management even more lightweight, enabling seamless use of JavaScript without the need for a separate build step.

  • Security Enhancements: Rails is known for its strong security features, and future versions will likely continue to focus on improving security practices. This could include updates to cross-site scripting (XSS) protection, content security policies, and encrypted cookies. Staying up to date with these security enhancements will help protect Book Bazaar from potential vulnerabilities and ensure the safety of user data.

  • Compatibility with Ruby Versions: As Ruby continues to evolve, Rails will need to maintain compatibility with the latest Ruby versions. Future updates may include optimizations for Ruby 3.1 or Ruby 4, taking advantage of new language features and performance improvements.

Conclusion

By keeping track of upcoming Rails versions, you can ensure that Book Bazaar stays up to date with the latest features, improving both its functionality and its long-term viability.

In this tutorial, we have successfully walked through the process of building a headless CMS using Ruby on Rails. From setting up the development environment and configuring the database to implementing advanced features like pagination, SEO optimization, and API management, you’ve gained the essential skills required to build a scalable and maintainable CMS.

The flexibility of a headless CMS, coupled with the powerful tools provided by Rails, enables developers to create modern, API-first applications that can integrate seamlessly with a wide range of front-end frameworks. As you continue to expand your knowledge of Rails and explore further advancements in web development, the concepts covered in this tutorial will serve as a solid foundation for building dynamic, content-driven websites and applications.

The field of headless CMS is growing rapidly, and mastering it opens opportunities to work with cutting-edge technologies and design solutions that meet the demands of modern digital platforms. We encourage you to continue experimenting with these concepts and explore new ways to enhance and optimize your CMS projects.

References

  1. Ruby on Rails Official Documentation
    https://guides.rubyonrails.org

  2. Kaminari Pagination Gem
    https://github.com/kaminari/kaminari

  3. FriendlyId SEO Slug Gem
    https://github.com/norman/friendly_id

  4. Docker Documentation
    https://docs.docker.com/

  5. MySQL Documentation
    https://dev.mysql.com/doc/

  6. Postman API Testing Tool
    https://www.postman.com/

  7. Headless CMS Trends
    "The Rise of Headless CMS and What it Means for Developers"

  8. Rails API Best Practices
    https://medium.com/rubycademy/rails-api-best-practices

  9. Shopify Headless CMS
    https://www.shopify.com/enterprise/headless-commerce