A simple, fast, and maintainable blog system built with Ruby on Rails that uses markdown files for content storage. Perfect for developers who want to write in markdown while having the power of Rails for dynamic features.
- Markdown-based content - Write content in simple, readable markdown files
- Dynamic markdown content - Use ERB syntax within
.md.erbfiles for dynamic content - Internal linking - Seamless navigation between markdown pages
- No database required for content - All content stored as files in the filesystem
- Real-time data - Current date, time, Rails version, environment info
- ERB integration - Full access to Rails helpers, variables, and environment
- Conditional content - Show different content based on environment or conditions
- Dynamic loops - Generate lists and repeated content programmatically
- Rails helpers - Access to all Rails view helpers within markdown
- Modern web design - Responsive design with beautiful typography
- Clean URLs - Simple routing like
/page-namefor markdown files - Fast loading - File-based content with efficient caching
- Mobile-friendly - Responsive design that works on all devices
- Security-first design - Whitelist-based file access prevents path traversal attacks
- Zero security warnings - Passes Brakeman security scanning
- Input validation - Strict validation of all user inputs
- CI/CD pipeline - Automated security scanning, linting, and testing
- Fast development - Hot reloading in development mode
- Reproducible environment - NixOS shell.nix for consistent development setup
- Comprehensive testing - Full CI pipeline with security, style, and unit tests
- Git workflow - Feature branches with squash merges for clean history
- Backend: Ruby on Rails 8.1.1
- Ruby Version: 3.2.9
- Markdown Processing: Redcarpet gem
- Template Engine: ERB for dynamic content
- Development Environment: NixOS with shell.nix
- Web Server: Puma (port 9955)
- Database: SQLite (for Rails features, not content)
- NixOS or Nix package manager
- Git
-
Clone the repository
git clone https://github.com/jannapps/dollhouse-blog.git cd dollhouse-blog -
Enter development environment
nix-shell
-
Install dependencies
bundle install
-
Start the server
bin/rails server --port=9955
-
Visit your blog Open http://localhost:9955 in your browser
Create .md files in the posts/ directory:
# My New Page
This is a simple markdown page with **bold text** and [links](/).
## Features
- Lists work great
- So do code blocksCreate .md.erb files for dynamic content:
# Welcome Page
Today is: <%= Date.current.strftime("%A, %B %d, %Y") %>
<% if Rails.env.development? %>
## Development Mode
Debug features are available!
<% end %>
## Random Numbers
<% 3.times do |i| %>
<%= i + 1 %>. Lucky number: **<%= rand(1..100) %>**
<% end %>Files are automatically accessible via clean URLs:
posts/about.mdβ/aboutposts/contact.md.erbβ/contactposts/blog-post.mdβ/blog-post
Always run the complete CI suite before pushing:
# Complete CI pipeline
nix-shell --run "bin/brakeman" && \
nix-shell --run "bin/bundler-audit check --update" && \
nix-shell --run "bin/rubocop -a" && \
nix-shell --run "bin/rails test"- Create feature branches for all changes
- Run CI locally before committing
- Use squash merges to main branch
- Keep commit history clean and descriptive
- Never use user parameters directly in file operations
- Use whitelist-based file access with pre-approved mappings
- Implement strict input validation (alphanumeric, dash, underscore only)
- Always validate file paths are within expected directories
dollhouse-blog/
βββ app/
β βββ controllers/
β β βββ home_controller.rb # Homepage controller
β β βββ pages_controller.rb # Dynamic markdown page handler
β βββ views/
β βββ home/
β β βββ index.html.erb # Homepage template
β βββ pages/
β βββ show.html.erb # Markdown page template
βββ posts/ # Markdown content directory
β βββ home.md # Homepage content
β βββ test.md # Example static page
β βββ dynamic-example.md.erb # Example dynamic page
βββ config/
β βββ routes.rb # Dynamic routing configuration
βββ shell.nix # NixOS development environment
βββ CLAUDE.md # Development notes and CI process
βββ README.md # This file
The blog supports a flexible layout system using YAML frontmatter to specify different page layouts and widgets.
- β single-column - Clean single column layout for focused content
- β two-column - Main content with sidebar for widgets
- β three-column - Main content with dual sidebars (nav + widgets)
- β card-grid - Grid layout for post listings, galleries, or portfolios
- β masonry - Pinterest-style staggered grid for mixed content sizes
- β full-width - Edge-to-edge content without container constraints
- β narrow - Extra-narrow layout for long-form reading
- β split-screen - Half content, half media layout
- β hero-banner - Large header section with content below
- β timeline - Chronological content with date markers
- β comparison - Side-by-side content blocks
- β landing-page - Multi-section layout with different backgrounds
- β mobile-first-stack - Responsive stacking layout
- β sidebar-overlay - Sidebar becomes slide-out drawer on mobile
Add YAML frontmatter to your markdown files:
---
layout: two-column
title: My Page Title
sidebar: recent-posts
---
# My Content
This content will be displayed in a two-column layout with a sidebar widget.- Homepage:
/- Static markdown content with feature overview - Test Page:
/test- Simple static markdown example - Dynamic Example:
/dynamic-example- Comprehensive ERB features demo - Layout Example:
/layout-example- Two-column layout with sidebar widget
The project includes comprehensive automated testing:
- Brakeman: Security vulnerability scanning
- bundler-audit: Dependency security checking
- RuboCop: Code style and linting
- Rails Tests: Application testing
All checks must pass before merging to main branch.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Run CI locally to ensure all checks pass
- Commit your changes with descriptive messages
- Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request with squash merge
This project is open source and available under the MIT License.
- Repository: https://github.com/jannapps/dollhouse-blog
- Live Demo: http://localhost:9955 (after running locally)
Note that this will build a production server.
-
Generate a secret key
ruby -e "require 'securerandom' puts \"SECRET_KEY_BASE=#{SecureRandom.hex(64)}\"" > .env
-
Build the container
docker build -t dollhouse_blog . -
Run the container
docker run -it -p 80:80 dollhouse_blog
-itis required as otherwise you won't be able to use CTRL-C to exit the server.
Built with β€οΈ using Ruby on Rails and markdown