GSD
How to Build a Knowledge Base with Ruby and ButterCMS
Posted by Eze Nnaemeka on September 25, 2023
In today's digital landscape, having a centralized repository of information is crucial for individuals and organizations alike. Imagine a valuable resource that enables effortless access to information, solutions, and answers to specific questions or problems.
Enter the knowledge base, a dynamic solution designed to store and organize knowledge in a structured manner. By utilizing categories, tags, and a hierarchical structure, information becomes easily navigable, ensuring swift retrieval. Incorporating intelligent search functionalities based on keywords or phrases further streamlines the process.
Whether you're a product-focused business seeking to create a self-service library for your customers or a customer support team tired of repeatedly addressing the same inquiries, building a knowledge base is the answer. In this tutorial, we'll explore how you can harness the power of Ruby and ButterCMS to craft an exceptional Ruby knowledge base website, elevating customer satisfaction and revolutionizing information management.
Table of contents
Understanding Ruby
Ruby is a programming language that is dynamic and object-oriented. It is known for its simplicity and readability. It provides a clean and intuitive syntax that is easy to understand and write. Many developers prefer Ruby because it has numerous features, which include:
Simplicity for quick development: Ruby is a straightforward and expressive programming language that allows programmers to write code quickly and effectively. This makes it simple to create a knowledge base quickly and with the least effort, especially when combined with Sinatra's minimalist interface and modular design.
Caching: Ruby provides a variety of caching mechanisms, such as built-in caching libraries (e.g., ActiveSupport::Cache) and popular third-party gems (e.g., Redis). Caching frequently accessed data or expensive computations can significantly improve a knowledge base's performance and scalability by reducing the database's load and optimizing response times.
Dynamic Nature: Ruby is a dynamically typed language, meaning that you can modify objects and classes during runtime. This flexibility allows you to create dynamic, adaptable features in your knowledge base. For example, you can easily add new attributes or methods to objects, change their behavior on the fly, or implement dynamic plugins or extensions. The dynamic nature of Ruby promotes agile development and enables rapid prototyping and iteration.
Metaprogramming Capabilities: Ruby's metaprogramming abilities allow developers to modify and extend the language dynamically. This enables the creation of DSLs (Domain-Specific Languages) and the implementation of powerful abstractions that can make your knowledge base codebase more expressive and flexible.
Why use ButterCMS
ButterCMS is a headless content management system that empowers developers to effortlessly handle and share content across their websites and applications utilizing a RESTful API. Due to its headless approach users can efficiently manage content with ease. There are several compelling reasons to utilize ButterCMS for your knowledge base application, which include:
-
WYSIWYG editor: Creating and editing content with ButterCMS is a breeze, thanks to its intuitive WYSIWYG (What You See Is What You Get) editor. You can easily manage and preview your content in real-time without coding expertise.
-
Page types: Page types serve as templates when creating pages on ButterCMS. These templates have different content fields that can hold various types of content. In building the pages for the knowledge base, we will utilize page types to generate templates.
-
Collections: ButterCMS provides a structured way to store and retrieve content within ButterCMS, making it easier to handle and present data consistently across your website or application. We'll make use of the collection feature to categorize our knowledge base.
Tutorial: Building a knowledge base with Ruby and ButterCMS
In this tutorial, we will build a knowledge base application for Drop.com inspired by examples of knowledge bases on Search Engine Journal with Ruby Sinatra powered by ButterCMS; we’ll also look at how to categorize our knowledge base using the collections feature. Here’s a preview of what we’ll be building.
All the code for this tutorial can be found in the following GitHub repo.
Tutorial Prerequisites
To get along with this tutorial, you'll need
-
A basic understanding of Ruby and Sinatra
-
ButterCMS account
-
Code Editor
-
Ruby and Sinatra installed on your local machine
Setting up our knowledge base article page type
In this section, we will focus on setting up the knowledge base article page type.
First, head to the ButterCMS official website and sign up. Then, you'll be directed to the ButterCMS dashboard.
In order to create our article page, we must first categorize our pages using the collection feature. This will allow us to use collections as filterable properties for our pages.
Building the category collection
To create a collection, go to the New Collection Configuration page by hovering over the Content Types icon on the left sidebar and clicking on the "+" icon located next to the Collections.
In the collection configuration, we’d be adding two fields:
-
Short Text → “name”
-
Short Text → “slug”
To save this collection, enter the Kb_category as the name and click the Save as a collection button.
Next, we’d populate our collection items to represent our defined categories by assigning an appropriate name and slug to each collection item and then clicking the Publish button. This helps in providing clear and concise information about the content focus.
Now, we can go ahead and build our article page and make reference to our newly built collection.
Creating the knowledge base article page
To access the Content Types section on the ButterCMS dashboard, hover over it and select the Page Types option by clicking the "+" symbol.
Following that, we’d be directed to an empty Page Type page where we can configure our page.
In the Page Type configuration, we’ll add the following fields:
-
Short Text => title
-
WYSIWYG => body
-
Reference => kb_category (this references a collection that’s created to help categorize our content)
And then, we’ll save the Page Type as “Drop Knowledge Base” and click on the Save as a Page Type.
Our page is now ready for some valuable content related to Drop.com. To enhance our user experience, we will address some Frequently Asked Questions.
Creating an article using the article page type
To add content to our newly created Page Type, hover over the Pages tab at the sidebar and click the “+” button attached.
After clicking the ”+”, you will be directed to a page where you can easily input all your required content. There, you need to provide the page title and API slug as metadata and then click the Save Page Metadata button to save your content and proceed to the text editor.
Now, we can fill in the different fields with our own content.
To add our reference, click on Add reference and select the item we added in our collection (payment). This way, this page will be categorized under payment.
Then, we click the useSelected button.
Now we’ve added our content to the knowledge base, let’s click on the Publish button.
Integrating ButterCMS with Ruby
Let’s head to our code editor and create this folder structure and these files in our newly created folder.
📦Ruby-ButterCMS-KB
┣ 📂Public
┃ ┗ 📜styles.css
┣ 📂views
┃ ┣ 📜detail.erb
┃ ┣ 📜index.erb
┃ ┗ 📜filter.erb
┗ 📜app.rb
To integrate ButterCMS with our Ruby application, we only need a secret key that can be easily obtained from the Settings section on the ButterCMS website.
Let's copy our secret key, which we'd use to fetch our data from ButterCMS.
In our code editor, let's head over to our app.rb file and copy and paste the following code:
HomePage
In this section, we’ll retrieve our content from Butter and display them in our application.
require 'sinatra'
require 'net/http'
require 'json'
set :public_folder, File.join(File.dirname(__FILE__), 'public')
get '/' do
uri = URI('YOUR API KEY') # Replace with your API endpoint
response = Net::HTTP.get(uri)
data = JSON.parse(response)
erb :index, locals:{data: data}
end
Our project uses the Sinatra web framework to create a fast and efficient Index route (/). Whenever a user visits the homepage, our code smoothly pulls data from a remote API using the Net::HTTP library and quickly parses it as JSON with the JSON library. We then display the data in an HTML template using the ERB templating engine, passing the fetched data as a local variable called "data" using the locals option of the ERB method. To ensure that CSS, JavaScript, and images are delivered seamlessly, we use the set method to specify the public folder's location. We also use our knowledge of the File.join and File.dirname(__FILE__) methods to construct a file path to the public folder based on the current file's location.
Next, we’d update our index.erb file with the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/styles.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Tajawal:wght@200;300;400;500;700;800&display=swap"
rel="stylesheet"
/>
<title>Document</title>
</head>
<body>
<nav>
<div class="logoContainer">
<img
src="https://theme.zdassets.com/theme_assets/789182/2a7764f7c4eb8f84766edad7c654c021a20e7300.png"
height="30px"
/>
</div>
<div class="navBox">
<div class="navItem">Help</div>
<div class="navItem active">FAQ</div>
<div class="navItem">Contact</div>
<div class="navItem">About us</div>
</div>
</nav>
<div class="faq_text">
<h3>Frequently Asked Questions</h3>
<h4>Need help? We've got you covered</h4>
</div>
<div class="faq_body">
<div class="faq_body_inner">
<div class="faq_category_body">
<h3>Filter by Category:</h3>
<div>
<form method="get" action="/filter">
<select name="dropdown">
<option value="introduction">Introduction</option>
<option value="payment">Payment</option>
</select>
<input type="submit" value="Submit" class="btn" />
</form>
</div>
</div>
</div>
<div class="faq_items_body">
<% data['data'].each do |data|%>
<div class="card">
<h3><%= data['fields']['title'] %></h3>
<%= data['fields']['body'].slice(0, 150) %>...
<a href="/detail/<%= data['slug'] %>">See more</a>
</div>
<% end %>
<!-- -->
</div>
</div>
</body>
</html>
In the above code, we added a Navigation bar with the Drop.com logo and links to different pages, a dropdown filter which which we can use to filter our knowledge base and all FAQ’s which we retrieved from ButterCMS.
DetailPage
In the index.erb file, when we click on a FAQs post, we need to be redirected to a separate page to view all the post's details, such as the body. Therefore, we will establish another route that accepts parameters to achieve this.
Let's head over to our app.rb file and update it by adding the following code:
get '/detail/:slug' do
slug = params[:slug]
uri = URI('https://api.buttercms.com/v2/pages/drop_knowledge_base/' + slug + '/?auth_token="YOUR API-KEY"') # Replace with your API endpoint
response = Net::HTTP.get(uri)
data = JSON.parse(response)
puts data
erb :detail, locals:{data:data}
end
Next, we’d update our detail.erb file with the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/styles.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Tajawal:wght@200;300;400;500;700;800&display=swap"
rel="stylesheet"
/>
<title>Document</title>
</head>
<body>
<nav>
<div class="logoContainer">
<img
src="https://theme.zdassets.com/theme_assets/789182/2a7764f7c4eb8f84766edad7c654c021a20e7300.png"
height="30px"
/>
</div>
<div class="navBox">
<div class="navItem">Help</div>
<div class="navItem active">FAQ</div>
<div class="navItem">Contact</div>
<div class="navItem">About us</div>
</div>
</nav>
<div class="faq_text">
<h3>Frequently Asked Questions</h3>
<h4>Need help? We've got you covered</h4>
</div>
<div class="faq_body">
<div class="faq_body_inner">
<div class="faq_category_body category">
<h3>Filter by Category:</h3>
</div>
</div>
<div class="faq_body">
<div class="faq_body_inner detail">
<h3><%= data['data']['fields']['title']%></h3>
<%= data['data']['fields']['body']%>
</div>
</div>
</div>
</body>
</html>
Here’s a preview of our Detail page
Adding a filtering functionality
To add the filtering functionality, We need to create a new route that accepts parameters to view FAQ posts associated with the selected option from the dropdown in the index.erb file.
Next, we’d update our app.rb file:
get '/filter' do
slug = params[:dropdown]
uri = URI('https://api.buttercms.com/v2/pages/drop_knowledge_base/?&fields.category.slug=' + slug + '&auth_token=YOUR API-KEY') # Replace with your API endpoint
response = Net::HTTP.get(uri)
data = JSON.parse(response)
puts slug
erb :filter,locals:{data:data, slug:slug}
end
Next, we’d update our filter.erb file with the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/styles.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Tajawal:wght@200;300;400;500;700;800&display=swap"
rel="stylesheet"
/>
<title>Document</title>
</head>
<body>
<nav>
<div class="logoContainer">
<img
src="https://theme.zdassets.com/theme_assets/789182/2a7764f7c4eb8f84766edad7c654c021a20e7300.png"
height="30px"
/>
</div>
<div class="navBox">
<div class="navItem">Help</div>
<div class="navItem active">FAQ</div>
<div class="navItem">Contact</div>
<div class="navItem">About us</div>
</div>
</nav>
<div class="faq_text">
<h3>Frequently Asked Questions</h3>
<h4>Need help? We've got you covered</h4>
</div>
<div class="faq_body">
<div class="faq_body_inner">
<div class="faq_category_body">
<h3>Filter by Category:</h3>
<div>
<h3><%= slug %></h3>
</div>
</div>
</div>
<div class="faq_items_body">
<% data['data'].each do |data|%>
<div class="card">
<h3><%= data['fields']['title'] %></h3>
<%= data['fields']['body'].slice(0, 150) %>...
<a href="/detail/<%= data['slug'] %>">See more</a>
</div>
<% end %>
<!-- -->
</div>
</div>
</body>
</html>
Now, we’re done updating our file, let’s see what our application looks like:
Final thoughts
Congratulations! You've made it to the end of the tutorial. By now you should have created a Ruby knowledge base website powered by ButterCMS. Over the course of this tutorial, you've learned how to create pages effortlessly, organize your knowledge base with collections, and explored other vital topics. But this is just the beginning.
If you're hungry for more knowledge and eager to enhance the functionalities of your Ruby application, don't hesitate to dive into ButterCMS's official documentation for Ruby. Additionally, we recommend you check out the following tutorials to see ButterCMS and Ruby in action.
- How to Add a Powerful Blog to Your Ruby Application with ButterCMS
- Ruby App Tutorial: Building Landing Pages from Scratch with ButterCMS
ButterCMS is the #1 rated Headless CMS
Related articles
Don’t miss a single post
Get our latest articles, stay updated!
Self-driven engineer with over 3 years of experience that places figuratively cutting-edge collaborative and team efforts. Who's currently focused on developing advanced software development and leadership skills.