This article discusses building a real-time collaborative Markdown editor as part of a Devtools Startup series. Emphasizing the growing demand for collaborative editing tools among distributed teams, it advocates using Ruby on Rails and Redis for development.
In this article, we will continue our Devtools Startup series. In earlier articles in this series, we have talked about:
- Devtools Startup Ideas: Building an AI-Powered Debugging Assistant With Code Samples!
- DevTools Startup Ideas: Build an AI-Powered Chatbot Using Claude And React
Today, we will be looking at the prospects of building a real-time markdwon editor as a startup founder.
For founders and entrepreneurs looking to enter the text-editor devtools startup space, this ruby on rails tutorial on building a realtime markdown editor using Ruby on Rails and Redis presents an exciting opportunity.
This article explores how to create such a product and why it could be a viable business venture.
The Growing Market for Developer Tools
The devtools startup ecosystem has seen remarkable growth in recent years. With developers increasingly working in distributed teams, there’s a rising demand for collaborative editing tools. A realtime markdown editor fits perfectly into this niche, offering teams a seamless way to create and edit documentation, technical specs, and other content simultaneously.
Why Build With Rails and Redis?
Advantages Of Ruby On Rails For Projects
Ruby on Rails remains a powerful framework for building web applications, offering:
- Rapid development cycles
- Rich ecosystem of gems
- Strong convention over configuration principles
- Excellent websocket support through Action Cable
- Mature ORM with Active Record
- Using Redis as the Real-time Backend
Redis serves as an ideal backbone for real-time features because of its:
- In-memory data structure store capabilities
- Pub/Sub functionality
- Low latency operations
- Built-in support for data structures
- Excellent integration with Rails
Markdown editors are essentially tools for developers and writers but can be used in other fields. Combining this with real-time collaboration transforms a simple markdown editor into a powerful business goldmine.
Building A Real-Time Collaborative Markdown Editor With Rails and Redis
A collaborative Markdown editor where:
- Multiple users can edit the same document in real-time.
- Markdown content updates live for all collaborators.
- A live preview displays rendered Markdown alongside the editor.
Features
- User-friendly Markdown editor using CodeMirror.
- Real-time updates powered by ActionCable and WebSockets.
- Markdown rendering with marked.js.
- Bootstrap integration for a polished UI.
Tech Stack
- Backend: Ruby on Rails
- Frontend: CodeMirror, https://github.com/markedjs/marked, Bootstrap/Tailwind.
- Real-Time Communication: ActionCable
- Deployment: CodeSandbox or any cloud platform like Heroku.
This app was developed on this Sandbox.
Step 1: Set Up the Rails Project
Create a New Rails App
Start by creating a Rails project.
rails new markdown_editor --javascript=importmap
cd markdown_editor
Install dependencies for Redis and WebSockets:
# Add Redis and Foreman to the Gemfile
gem 'redis'
gem 'foreman', group: :development
run:
bundle install
Step 2: Configure Real-Time Collaboration
Enable ActionCable
Configure ActionCable to use Redis as the backend for WebSockets. Go to the directory config/cable.yml
and ensure it is configured this way.
development:
adapter: redis
url: redis://localhost:6379/1
Start/run Redis locally in your terminal:
redis-server
Generate a Channel
Next, we’d create an ActionCable channel to handle real-time document updates. In your terminal:
rails generate channel Document
- Navigate to this directory:
app/channels/document_channel.rb
and ensure that this is what you have on it.
class DocumentChannel < ApplicationCable::Channel
def subscribed
document = Document.find(params[:id])
stream_for document
end
def receive(data)
document = Document.find(data["id"])
document.update(content: data["content"])
DocumentChannel.broadcast_to(document, data)
end
end
Step 3: Building A Markdown Editor In Ruby On Rails
Add a Document Model
Generate a Document model to store the title
and content
:
rails generate model Document title:string content:text
rails db:migrate
Configure Routes and Controller
Let’s define the routes for our documents. Navigate to the config/routes.rb directory
and update it with.
Rails.application.routes.draw do
root 'documents#index'
resources :documents, only: [:index, :show, :new, :create, :update]
end
- We’d create our documents_controller.rb file and populate it.
class DocumentsController < ApplicationController
def index
@documents = Document.all
end
def show
@document = Document.find(params[:id])
end
def new
@document = Document.new
end
def create
@document = Document.new(document_params)
if @document.save
redirect_to document_path(@document)
else
render :new
end
end
def update
@document = Document.find(params[:id])
@document.update(document_params)
head :ok
end
private
def document_params
params.require(:document).permit(:title, :content)
end
end
Let’s build the frontend
Use CodeMirror for a rich Markdown editing experience and marked.js for live rendering. In our app/views
directory, let us create a new folder documents
and in it, create a show.html.erb
file
<div class="container mt-5">
<h1><%= @document.title %></h1>
<div class="row">
<!-- Editor -->
<div class="col-md-6">
<h3>Markdown Editor</h3>
<div id="editor" style="height: 500px; border: 1px solid #ddd;"></div>
</div>
<!-- Preview -->
<div class="col-md-6">
<h3>Live Preview</h3>
<div id="preview" class="border p-3 bg-light" style="height: 500px; overflow-y: auto;"></div>
</div>
</div>
</div>
<script>
// Initialize CodeMirror
const editor = CodeMirror(document.getElementById('editor'), {
value: "<%= j @document.content %>",
mode: "markdown",
lineNumbers: true,
});
// Reference the preview element
const preview = document.getElementById('preview');
// Function to render Markdown using marked.js
const renderMarkdown = (markdown) => {
try {
preview.innerHTML = marked.parse(markdown); // Render Markdown to HTML
} catch (error) {
console.error("Error rendering Markdown:", error);
}
};
// Initial render on page load
renderMarkdown(editor.getValue());
// Set up ActionCable
const cable = ActionCable.createConsumer();
const documentChannel = cable.subscriptions.create(
{ channel: "DocumentChannel", id: "<%= @document.id %>" },
{
received(data) {
// Update editor and preview when receiving data
editor.setValue(data.content);
renderMarkdown(data.content);
}
}
);
// Handle editor changes
editor.on("change", () => {
const markdown = editor.getValue();
renderMarkdown(markdown); // Update preview
// Send data to the ActionCable channel
documentChannel.send({ id: "<%= @document.id %>", content: markdown });
});
</script>
We would also be creating views for our homepage and our new document page.
new.html.erb
<div class="container mt-5">
<h1 class="mb-4">Create a New Document</h1>
<%= form_with(model: @document, local: true, class: "needs-validation", novalidate: true) do |form| %>
<div class="mb-3">
<%= form.label :title, "Title", class: "form-label" %>
<%= form.text_field :title, class: "form-control", placeholder: "Enter document title", required: true %>
</div>
<div class="mb-3">
<%= form.label :content, "Content", class: "form-label" %>
<%= form.text_area :content, class: "form-control", rows: 10, placeholder: "Enter markdown content here", required: true %>
</div>
<div class="d-flex justify-content-between mt-4">
<%= link_to "Back", documents_path, class: "btn btn-secondary" %>
<%= form.submit "Create Document", class: "btn btn-primary" %>
</div>
<% end %>
</div>
index.html.erb
<div class="container mt-5">
<h1 class="mb-4 text-bg">Documents</h1>
<div class="d-flex justify-content-between align-items-center mb-3">
<p class="text-muted">Manage your documents below.</p>
<%= link_to "Create New Document", new_document_path, class: "btn btn-success" %>
</div>
<% if @documents.any? %>
<table class="table table-striped table-hover">
<thead class="table-dark">
<tr>
<th>Title</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% @documents.each do |document| %>
<tr>
<td><%= document.title %></td>
<td>
<%= link_to "View", document_path(document), class: "btn btn-sm btn-primary" %>
<%= link_to "Edit", document_path(document), class: "btn btn-sm btn-warning" %>
<%= link_to "Delete", document_path(document), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-sm btn-danger" %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p class="alert alert-warning">No documents found. <%= link_to "Create one now", new_document_path, class: "alert-link" %>.</p>
<% end %>
</div>
Step 4: Polish with Bootstrap or Tailwind
Integrate Bootstrap or Tailwind for a polished UI.
In your application.html.erb
file, add the bootstrap CDN.
If you are using Tailwind, find the Tailwind configurations for Rails on their official docs page.
For Bootstrap CDN:
<head>
<title>MarkdownEditor</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
</head>
Step 5: Run and Test
Start Redis and the Rails server:
redis-server & rails server -b 0.0.0.0 -p 3000
Navigate to /documents and test the editor.
These are the views you’d be generating when you run the app.
This is the homepage of the app. As you can see, I have been creating some documents as tests. My demo app also lacks some basic styles, however. 😅😅
You end up here when you click on the “create new document” button. This allows you to create a new document with a title and content.
This is what the live preview looks like!
Potential Startup Opportunities For A Collaborative Markdown Editor
Subscription Plans: Offer a premium version with additional features like version control or authentication.
Integration: Integrate with popular tools like GitHub, Slack, or Trello.
Team Collaboration: Build team-specific features like commenting or tracked changes.
Business Model and Market Opportunity For Founders and Investors
Target Market
- Software development teams
- Technical writing teams
- Documentation specialists
- Open source project maintainers
- Technical bloggers
Monetization Strategies For Founders and Investors
Freemium Model
- Basic features free for individual users
- Team features in paid tiers
- Enterprise plans with custom features
Pricing Tiers
- Individual: Free
- Team: $12/user/month
- Business: $25/user/month
- Enterprise: Custom pricing
Market Differentiation
- Focus on developer experience
- Git-like version control
- Advanced markdown extensions
- API access for automation
- Self-hosting options
Growth Strategy For Startup Founders And Investors
Initial Launch
- Build MVP with core features
- Launch on Product Hunt
- Engage with developer communities
- Collect early user feedback ###Scaling Phase
- Implement user feedback
- Add integration capabilities
- Build marketplace for extensions
- Develop enterprise features
Marketing Channels
- Developer conferences
- Technical blogs
- Developer podcasts
- GitHub marketplace
- Developer newsletters
Future Expansion Opportunities
- Feature Roadmap
- AI-powered writing assistance
- Custom markdown extensions
- Advanced collaboration tools
Integration with popular dev tools
- Mobile applications
- GitHub
- GitLab
- Jira
- Slack
- VS Code
With this, You’ve built a fully functional, real-time collaborative Markdown editor using Rails! This tool combines the power of Rails’ backend with rich frontend capabilities to deliver a seamless experience. With further enhancements, this idea could transform into a powerful Devtools startup.
Remember that success in the devtools startup space requires both technical excellence and business acumen. Focus on building a product that developers love while maintaining a sustainable business model.
This entire content is repurposed from the ongoing series on Devtools Startup Ideas on The Handy Developers' Guide.
Top comments (2)
Great 🔥 I will give this a full read later.
Awesome!