Diagrammer
Diagrammer is a Rails gem that generates a standalone, interactive database relationship diagram from ActiveRecord models.

It introspects your Rails application, reads model columns and associations, and writes a single browser-friendly HTML file. The diagram renders as draggable table cards — similar in spirit to dbdiagram.io — directly in the browser. The main design goal is a zero-dependency workflow: no Graphviz, no system packages, no local diagram renderer, no PDF toolchain, and no network access required to view the result.
Problem It Solves
In many Rails applications, the actual domain model becomes hard to understand from migrations, schema files, and model files alone. Developers often need to answer practical questions before making a safe change:
- Which models exist in the application?
- Which tables are connected?
- Which columns are primary keys and foreign keys?
- What does this part of the data model look like before a refactor?
- How can a team share a schema overview without installing Graphviz or using an external SaaS?
Diagrammer solves this by generating a visual relationship map directly from the Rails app. It uses ActiveRecord models as the source of truth and produces a standalone HTML file that can be opened in a browser, committed to documentation, shared in pull requests, or used during onboarding.
Why This Gem Exists
Rails projects often accumulate relationships faster than the schema stays understandable. Existing tools can work well, but they commonly require Graphviz, generate static image files, depend on an external service, or need extra setup that makes them inconvenient in Docker, CI, or onboarding workflows.
Diagrammer takes a simpler approach:
- Use Rails and ActiveRecord reflection as the source of truth.
- Generate a portable HTML file that can be opened in any browser.
- Render in the browser with a small inline script — no Graphviz, no CDN, no external service.
- Keep the output easy to understand and extend.
The Diagram
The generated page renders each table as a card and draws relationships between them:
- Table cards with a colored header (table name) and one row per column.
- Column details: name, ActiveRecord type, and
PK/FKbadges. - Relationship lines drawn as smooth curves. A line attaches to the foreign-key
column row when it can be inferred (an association named
teamanchors atteam_id); otherwise it attaches to the card edge. - Automatic layout via a built-in force-directed simulation with collision avoidance, so cards do not overlap on first render.
It is interactive:
- Scroll to zoom toward the cursor.
- Drag the background to pan.
- Drag a table to move it; dragging dims unrelated tables to highlight its neighbors.
- Re-layout re-runs the automatic layout, Fit frames the whole diagram, and Reset view restores the default zoom.
The full diagram spans the page width and is read-only.
Current Status
This project is an MVP. It is usable for small and medium Rails apps, but the API and output format may still change before a 1.0.0 release.
Currently supported:
- Rails rake task:
diagrammer:generate - Programmatic Ruby API:
Diagrammer.generate(...) - ActiveRecord model discovery through
ActiveRecord::Base.descendants - Rails eager loading before introspection
- Column rendering with type names
- Primary key marker:
PK - Foreign key marker for columns ending in
_id:FK - Association rendering for
belongs_to,has_one,has_many, andhas_and_belongs_to_many - Standalone, fully offline HTML output (no CDN, no network access)
Not implemented yet:
- Mounted Rails engine dashboard
- JSON export as a public API
- Model/table filtering options
- Polymorphic association visualization details
- STI-specific grouping
- Saved manual layout positions
- Direct PNG/SVG/PDF export
Requirements
- Ruby
>= 3.1 - Rails / Railties
>= 6.1 - ActiveRecord
>= 6.1 - Any modern browser to open the generated HTML file
The generated file is self-contained: all CSS and JavaScript are inlined and the table data is embedded as JSON. It needs no internet access to render, so it works in air-gapped environments, Docker, and offline machines.
Installation
For local development while this gem is not published yet, add it to a Rails application's Gemfile with a path:
gem 'diagrammer', path: '../diagrammer'
Then install dependencies:
bundle install
After the gem is published, the installation will become:
gem 'diagrammer', group: :development
Recommended usage is development-only. The gem introspects your application models and is intended as a developer tool, not a production runtime dependency.
How To Use
The normal workflow is:
- Add the gem to a Rails application.
- Run the generator task from the Rails app.
- Open the generated HTML file in a browser.
- Share or commit the file if the diagram should become part of the project documentation.
Generate dbdiagram.html in the Rails project root:
bin/rails diagrammer:generate
Open the generated file in a browser on macOS:
open dbdiagram.html
Open the generated file in a browser on Linux:
xdg-open dbdiagram.html
Generate to a custom path, for example inside a documentation directory:
bin/rails 'diagrammer:generate[docs/dbdiagram.html]'
The quotes around the task are recommended because some shells treat square brackets specially.
A typical documentation flow is:
mkdir -p docs
bin/rails 'diagrammer:generate[docs/dbdiagram.html]'
git add docs/dbdiagram.html
Programmatic Usage
You can generate a diagram from Ruby code:
Diagrammer.generate(output: Rails.root.join('dbdiagram.html'))
You can also pass a specific list of models. This is useful for tests, engines, or focused diagrams:
Diagrammer.generate(
output: Rails.root.join('billing_diagram.html'),
models: [Account, Invoice, Payment]
)
The method returns the output path as a string:
path = Diagrammer.generate(output: Rails.root.join('dbdiagram.html'))
puts path
What Gets Rendered
Each ActiveRecord model becomes a table card based on its database table name.
For every model, Diagrammer renders:
- Table name (card header)
- Columns
- Column ActiveRecord type, such as
integer,string,datetime,boolean - Primary key marker (
PK), based onmodel.primary_key - Foreign key marker (
FK), based on the_idcolumn suffix
Associations become relationship lines between cards. A model like this:
class User < ApplicationRecord
belongs_to :account
has_many :orders
end
produces a line from users to accounts (anchored at the account_id row when
present) and a line from users to orders.
Association Handling
Diagrammer discovers associations for these macros:
| ActiveRecord macro | Meaning |
|---|---|
belongs_to |
Source record references one target record |
has_one |
Source record has zero or one target record |
has_many |
Source record has zero or many target records |
has_and_belongs_to_many |
Many-to-many relationship |
An association is included only if its target table also belongs to the selected model set, which prevents external or unresolved associations from creating broken links. Relationship direction and optionality are not currently derived from validations or database constraints, so the diagram shows connectivity rather than exact cardinality.
How Model Discovery Works
The generator calls Rails eager loading before introspection:
Rails.application.eager_load!
Then it reads models from:
ActiveRecord::Base.descendants
A model is included only if it appears to be a concrete table-backed model:
- It responds to
table_name. - It responds to
columns. - It is not an abstract class.
table_exists?returns true.
Associations are discovered through:
model.reflect_on_all_associations
Output
By default the rake task writes:
dbdiagram.html
The HTML file contains:
- A responsive, full-width page layout
- The introspected schema embedded as JSON in a
<script type="application/json">block - An inline stylesheet and an inline renderer script that builds the cards, lays them out, draws the relationship lines, and wires up zoom / pan / drag
The file is self-contained and portable. It is meant to be committed to docs, attached to tickets, shared during onboarding, or generated temporarily during development.
Development
Install dependencies:
bundle install
Run the specs:
bundle exec rake spec
Run RuboCop:
bundle exec rubocop
Run the default task, which includes tests and linting:
bundle exec rake
Continuous Integration
The repository includes a GitHub Actions workflow in .github/workflows/ci.yml.
CI runs on:
- Pushes to
main - Pull requests
The workflow checks:
- Ruby
3.1 - Ruby
3.4 bundle exec rake specbundle exec rubocop
Project Structure
lib/diagrammer.rb
lib/diagrammer/generator.rb
lib/diagrammer/html_renderer.rb
lib/diagrammer/model_introspector.rb
lib/diagrammer/railtie.rb
lib/diagrammer/tasks/diagrammer.rake
spec/
Key files:
Diagrammer::ModelIntrospectorcollects models, columns, and associations into a plain Ruby hash.Diagrammer::HtmlRendererembeds that data as JSON in a standalone HTML page and ships the inline card renderer.Diagrammer::Generatorcoordinates introspection, rendering, and file writing.Diagrammer::Railtieloads the Rails rake task.
Known Limitations
The current implementation keeps the model simple. Be aware of these limitations:
- Foreign keys are detected by column name suffix only:
_id. - Database foreign key constraints are not inspected yet.
- Polymorphic associations may be skipped if
association.klasscannot be resolved. - STI models may produce output that needs refinement.
- Association optionality is not read from validations or database null constraints.
- Relationship lines anchor to a foreign-key row only when it can be inferred from the association name; otherwise they attach to the card edge.
- Automatic layout is not persisted between regenerations.
- Very large schemas (hundreds of tables) produce a large canvas; use zoom, pan, and drag to navigate.
Roadmap
Near-term improvements:
- Add filtering options for selected models and ignored tables.
- Add JSON output as a public API for richer interactive frontends.
- Improve polymorphic association handling.
- Add database foreign key constraint introspection.
- Add configurable output title and color themes.
- Make eager loading resilient to misconfigured host applications.
Larger features:
- Mountable Rails engine at
/diagrammerfor live diagrams in development. - Search, hide/show, and relationship highlighting in the viewer.
- Persisted layout positions per project.
- Export to SVG/PNG through browser-side rendering.
Design Principles
- No Graphviz dependency.
- No network dependency: the generated file renders offline.
- Prefer Rails reflection over parsing source files.
- Keep generated output easy to inspect and debug.
- Avoid production runtime assumptions.
- Make the MVP useful before adding a heavy frontend.
Contributing
Before opening a pull request, run:
bundle exec rake
When changing model introspection behavior, add specs around the generated intermediate data.
When changing HTML output, keep the generated file portable and offline, and avoid adding build steps unless there is a clear reason.
License
The gem is available as open source under the terms of the MIT License.