RailsTemplatable
A lightweight Rails Engine that enables any ActiveRecord model to use predefined templates for content management. Built with a simple one-to-many relationship, allowing each model instance to have one template while templates can be reused across multiple instances.
Features
- 🎯 Simple 1:N Relationship - Each record has one template, templates can be reused
- 📝 Multiple Content Formats - Support for HTML, Markdown, and plain text
- 🏷️ Flexible Categories - Pre-defined categories (feature_request, bug_report, etc.) or custom
- 🔗 Direct Foreign Key - No join table needed, cleaner database schema
- 🚀 Easy Integration - Simple concern-based inclusion
Installation
Add this line to your application's Gemfile:
gem "rails_templatable"And then execute:
$ bundle install
$ bin/rails railties:install:migrations FROM=rails_templatable
$ bin/rails db:migrateFor each model that will use templates, add a foreign key:
add_reference :posts, :template,
foreign_key: { to_table: :rails_templatable_templates },
index: falseQuick Start
1. Enable templates in your models
class Post < ApplicationRecord
include RailsTemplatable::HasTemplate
end
class WorkLog < ApplicationRecord
include RailsTemplatable::HasTemplate
end2. Create templates
# Feature request template
feature_template = RailsTemplatable::Template.create!(
category: "feature_request",
content: "# Feature Request\n\n## Description\n\n## Acceptance Criteria",
content_format: :markdown
)
# Bug report template
bug_template = RailsTemplatable::Template.create!(
category: "bug_report",
content: "## Bug Description\n\n## Steps to Reproduce\n\n## Expected Behavior",
content_format: :markdown
)3. Assign templates to records
post = Post.create!(
title: "Add user authentication",
content: "Implement OAuth2 login",
template: feature_template
)
# View template
post.template.category # => "feature_request"
post.template.content # => "# Feature Request..."Template Categories
Common template categories included:
| Category | Description |
|---|---|
feature_request |
Feature requests |
bug_report |
Bug reports |
tech_improvement |
Technical improvements |
meeting_note |
Meeting notes |
api_design |
API designs |
You can create any custom category as needed.
Relationship Model
One-to-Many (1:N)
- One Post/WorkLog instance → One Template
- One Template → Many instances
Example:
Post 1 → Template A (feature_request)
Post 2 → Template B (bug_report)
Post 3 → Template A (feature_request) # Reusable
Content Formats
Three content formats are supported:
-
html(0) - HTML content -
markdown(1) - Markdown content -
txt(2) - Plain text content (default)
RailsTemplatable::Template.create!(
category: "notification",
content: "Simple text notification",
content_format: :txt
)Query Examples
# Get a record's template
post.template
# Query by category
Post.joins(:template).where(rails_templatable_templates: { category: 'feature_request' })
# Get all records using a specific template
Post.where(template: feature_template)
# Query by content format
Post.joins(:template).where(rails_templatable_templates: { content_format: 1 })Database Schema
rails_templatable_templates
| Column | Type | Description |
|---|---|---|
category |
string | Template category (user-defined) |
content |
text | Template content |
content_format |
integer | Content format (0: html, 1: markdown, 2: txt) |
created_at |
datetime | Creation timestamp |
updated_at |
datetime | Update timestamp |
Target models (e.g., posts)
Add template_id foreign key:
| Column | Type | Description |
|---|---|---|
template_id |
integer | Foreign key to rails_templatable_templates |
Advanced Usage
Change template
# Assigning a new template replaces the old one
post.update(template: bug_template)
post.template.category # => "bug_report"Remove template
post.update(template: nil)
post.template # => nilAssign template after creation
post = Post.create(title: "New post")
post.update(template: feature_template)Migration Example
class AddTemplateToPosts < ActiveRecord::Migration[6.0]
def change
add_reference :posts, :template,
foreign_key: { to_table: :rails_templatable_templates },
index: false
end
endDevelopment
Running tests in the dummy app
cd test/dummy
ruby test_templatable.rbArchitecture
- Direct Foreign Key - No join table needed
- Simple & Clean - One record = One template
- Flexible - Templates can be changed anytime
- Efficient Queries - Direct JOIN without intermediate table
Comparison with N:N Design
If you need "one record has multiple templates", consider using a tag system or polymorphic many-to-many associations instead.
Why category instead of type?
We use category instead of type to avoid conflicts with Rails' Single Table Inheritance (STI) feature, which reserves the type column for storing class names.
Future Enhancements
- Template variable interpolation
- Template versioning
- Template inheritance
- Template preview functionality
- I18n multi-language support
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
The gem is available as open source under the terms of the MIT License.
Credits
Built with inspiration from rails_badgeable.