rails_visualizer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +36 -0
- data/LICENSE.txt +21 -0
- data/README.md +509 -0
- data/lib/rails_visualizer/assets/dist/index.html +76 -0
- data/lib/rails_visualizer/configuration.rb +35 -0
- data/lib/rails_visualizer/controllers_inspector.rb +200 -0
- data/lib/rails_visualizer/gems_inspector.rb +105 -0
- data/lib/rails_visualizer/introspector.rb +191 -0
- data/lib/rails_visualizer/jobs_inspector.rb +120 -0
- data/lib/rails_visualizer/mailers_inspector.rb +126 -0
- data/lib/rails_visualizer/migrations_inspector.rb +68 -0
- data/lib/rails_visualizer/path_helper.rb +29 -0
- data/lib/rails_visualizer/railtie.rb +9 -0
- data/lib/rails_visualizer/renderer.rb +31 -0
- data/lib/rails_visualizer/routes_inspector.rb +124 -0
- data/lib/rails_visualizer/schema/cache.rb +234 -0
- data/lib/rails_visualizer/schema/index_inspector.rb +43 -0
- data/lib/rails_visualizer/schema/model_inspector.rb +245 -0
- data/lib/rails_visualizer/serializer.rb +124 -0
- data/lib/rails_visualizer/version.rb +5 -0
- data/lib/rails_visualizer.rb +22 -0
- data/lib/tasks/rails_visualizer.rake +59 -0
- metadata +76 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 92930541e9b74dde2cddec0f9314b9204c05fad9151f2e4aac4b7415a4246f14
|
|
4
|
+
data.tar.gz: 7bb8078d83854514a4709a1b63446d3f6a951409f100e7310b8e13613004534f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ccd2f5078b94d8870991ea38d5e2ba646d49beee4b258b8693c628c5ea55678b56e76eaa723dcda881eea20b7d32023a550be6dc52a897b2092e79d03930387c
|
|
7
|
+
data.tar.gz: 86d1a1b4ff05263750292e56f15d7709b64a8e15bde8e47c577cd084ab1370304114672c4df8a37f88d715b71b9b3c222c5ac0ddbe335749807dc42cbee6cdbf
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-05-18
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `RailsVisualizer::Introspector` — orchestrates parallel inspection of all app layers using threads for I/O-bound work and fork-based workers for CPU-bound model inspection on large apps
|
|
15
|
+
- `RailsVisualizer::Schema::ModelInspector` — inspects ActiveRecord models for columns, associations, validations, enums, scopes, and lifecycle callbacks with shared file and method-location caches for performance
|
|
16
|
+
- `RailsVisualizer::Schema::Cache` — bulk-loads column and index metadata with PostgreSQL-optimised parallel SQL queries and a per-adapter fallback
|
|
17
|
+
- `RailsVisualizer::Schema::IndexInspector` — reads database indexes per table
|
|
18
|
+
- `RailsVisualizer::RoutesInspector` — collects all application routes with verb, path, controller, action, namespace, internal flag, and constraint data
|
|
19
|
+
- `RailsVisualizer::ControllersInspector` — collects ActionController classes with routable actions, public helpers, and before/after/around callbacks (including `only:`, `except:`, `if:`, `unless:` restrictions and inherited-from tracking)
|
|
20
|
+
- `RailsVisualizer::JobsInspector` — collects ActiveJob and Sidekiq worker classes with queue, priority, retry, and discard configuration
|
|
21
|
+
- `RailsVisualizer::MailersInspector` — collects ActionMailer classes with email action methods and default sender
|
|
22
|
+
- `RailsVisualizer::MigrationsInspector` — reads migration files and the `schema_migrations` table to report applied/pending status and summary counts
|
|
23
|
+
- `RailsVisualizer::GemsInspector` — reads Bundler gem dependencies with version, environment groups, source (RubyGems / GitHub / GitLab / path), and `require:` configuration
|
|
24
|
+
- `RailsVisualizer::Serializer` — converts introspection data to camelCase JSON with memoised key conversion
|
|
25
|
+
- `RailsVisualizer::Renderer` — injects JSON into a pre-built, self-contained React HTML template via a placeholder script tag
|
|
26
|
+
- `RailsVisualizer::Configuration` — configurable options: `excluded_models`, `output_path`, `open_browser`, `theme`, `verbose`
|
|
27
|
+
- `rails_visualizer` Rake task — single command: introspect → serialize → render → open browser
|
|
28
|
+
- 8-tab interactive HTML dashboard (Overview, Gems, Routes, Controllers, Models, Migrations, Jobs, Mailers) built with React 18, Tailwind CSS, and React Flow
|
|
29
|
+
- ER diagram canvas with automatic Dagre layout, zoom/pan, minimap, and a model detail sidebar
|
|
30
|
+
- Search bars, filter chips, and item counts across all tabs
|
|
31
|
+
- Health checks on the Overview tab with cross-tab navigation
|
|
32
|
+
- Light / dark / system theme support with localStorage persistence
|
|
33
|
+
- `IssuesOnly` filter to focus on models without validations, pending migrations, mailers without a default sender, and unrouted controller actions
|
|
34
|
+
|
|
35
|
+
[Unreleased]: https://github.com/rajkamallashkari/rails_visualizer/compare/v0.1.0...HEAD
|
|
36
|
+
[0.1.0]: https://github.com/rajkamallashkari/rails_visualizer/releases/tag/v0.1.0
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Raj Kamal Lashkari
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
# RailsVisualizer
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/rails_visualizer)
|
|
4
|
+
[](https://www.ruby-lang.org)
|
|
5
|
+
[](https://rubyonrails.org)
|
|
6
|
+
[](LICENSE.txt)
|
|
7
|
+
|
|
8
|
+
> One command. A full interactive dashboard for your Rails app.
|
|
9
|
+
|
|
10
|
+
RailsVisualizer introspects your Rails application and generates a **self-contained interactive HTML dashboard** — no server, no config, no Node.js required. Run one Rake task and explore your models, associations, routes, controllers, jobs, mailers, migrations, and gems through a polished 8-tab UI with search, filters, an ER diagram canvas, and built-in health checks.
|
|
11
|
+
|
|
12
|
+
The generated file contains **all JavaScript and CSS inline** — it works offline, loads instantly, and can be shared as a single file with zero external dependencies.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Table of Contents
|
|
17
|
+
|
|
18
|
+
- [Installation](#installation)
|
|
19
|
+
- [Quick Start](#quick-start)
|
|
20
|
+
- [Dashboard Tabs](#dashboard-tabs)
|
|
21
|
+
- [Overview](#overview)
|
|
22
|
+
- [Gems](#gems)
|
|
23
|
+
- [Routes](#routes)
|
|
24
|
+
- [Controllers](#controllers)
|
|
25
|
+
- [Models](#models)
|
|
26
|
+
- [Migrations](#migrations)
|
|
27
|
+
- [Jobs](#jobs)
|
|
28
|
+
- [Mailers](#mailers)
|
|
29
|
+
- [Configuration](#configuration)
|
|
30
|
+
- [Health Checks](#health-checks)
|
|
31
|
+
- [How It Works](#how-it-works)
|
|
32
|
+
- [Performance](#performance)
|
|
33
|
+
- [Compatibility](#compatibility)
|
|
34
|
+
- [FAQ](#faq)
|
|
35
|
+
- [Development](#development)
|
|
36
|
+
- [Contributing](#contributing)
|
|
37
|
+
- [License](#license)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
Add `rails_visualizer` to your `Gemfile`. Since it only introspects the app and is never needed in production, place it in the `development` group:
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
group :development do
|
|
47
|
+
gem 'rails_visualizer'
|
|
48
|
+
end
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Then run:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
bundle install
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
That's it — no generators, no migrations, no configuration files needed.
|
|
58
|
+
|
|
59
|
+
## Quick Start
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
bundle exec rake rails_visualizer
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This single command will:
|
|
66
|
+
|
|
67
|
+
1. Eager-load your Rails application.
|
|
68
|
+
2. Introspect models, routes, controllers, jobs, mailers, migrations, and gems.
|
|
69
|
+
3. Generate a self-contained HTML file at `tmp/rails_visualizer/index.html`.
|
|
70
|
+
4. Open it in your default browser automatically.
|
|
71
|
+
|
|
72
|
+
Example output:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
RailsVisualizer: Introspecting app...
|
|
76
|
+
✓ 47 models
|
|
77
|
+
✓ 128 routes
|
|
78
|
+
✓ 12 jobs
|
|
79
|
+
⚠ 31 controllers (3 actions without route)
|
|
80
|
+
⚠ 64 migrations (2 pending migrations)
|
|
81
|
+
✓ 4 mailers
|
|
82
|
+
RailsVisualizer: Rendering...
|
|
83
|
+
RailsVisualizer: Done → tmp/rails_visualizer/index.html
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The generated HTML file is completely standalone — email it, commit it, drop it in Slack, or open it on any machine. No server required.
|
|
87
|
+
|
|
88
|
+
## Dashboard Tabs
|
|
89
|
+
|
|
90
|
+
### Overview
|
|
91
|
+
|
|
92
|
+
The landing tab gives you a bird's-eye view of your entire application:
|
|
93
|
+
|
|
94
|
+
- **App header** — displays your app name, page title (extracted from the layout), favicon (auto-detected from `public/`), and version badges for Rails, Ruby, your database (PostgreSQL, MySQL, or SQLite), and background job processor (Sidekiq, GoodJob, Solid Queue, etc.).
|
|
95
|
+
- **Stats grid** — clickable cards for each area (Gems, Routes, Controllers, Models, Migrations, Jobs, Mailers) showing counts and sub-stats like HTTP verb breakdown, column counts, queue counts, and more. Warning badges appear on cards that have issues.
|
|
96
|
+
- **Health checks** — a prioritized checklist that surfaces problems across your codebase, with "Go to" links that navigate directly to the relevant tab. See [Health Checks](#health-checks) for the full list.
|
|
97
|
+
|
|
98
|
+
### Gems
|
|
99
|
+
|
|
100
|
+
Displays every dependency from your `Gemfile`:
|
|
101
|
+
|
|
102
|
+
- **Name**, **version**, and **version constraint** (e.g. `~> 7.0`).
|
|
103
|
+
- **Summary** pulled from the gem's metadata.
|
|
104
|
+
- **Environment groups** — color-coded chips for Common, Development, Test, and Production.
|
|
105
|
+
- **Source tags** — shows non-standard sources like `github: owner/repo`, `branch: main`, `path: engines/erp`, or `require: false`.
|
|
106
|
+
- **Homepage link** — external link icon for each gem.
|
|
107
|
+
- **Filters** — filter by environment group (Common, Development, Test, Production).
|
|
108
|
+
- **Search** — search across gem name, summary, and version.
|
|
109
|
+
|
|
110
|
+
### Routes
|
|
111
|
+
|
|
112
|
+
Shows every route defined in `config/routes.rb`:
|
|
113
|
+
|
|
114
|
+
- **HTTP verb** — color-coded badge (GET green, POST blue, PATCH/PUT amber, DELETE red).
|
|
115
|
+
- **Path** — with `:param` segments highlighted and `(format)` segments dimmed.
|
|
116
|
+
- **Controller#action** — linked pair showing the target.
|
|
117
|
+
- **Route name** — the named helper (e.g. `edit_user`).
|
|
118
|
+
- **Constraints** — any route constraints displayed as chips.
|
|
119
|
+
- **Orphaned route detection** — routes pointing to non-existent controllers are flagged with a red "Orphaned" badge.
|
|
120
|
+
- **Filters** — toggle by HTTP verb (GET, POST, PATCH, PUT, DELETE) and an "Issues only" toggle to show only orphaned routes.
|
|
121
|
+
- **Copy** and **Open in editor** buttons for path and controller file.
|
|
122
|
+
|
|
123
|
+
### Controllers
|
|
124
|
+
|
|
125
|
+
Namespace-grouped tree view of all your ActionController classes:
|
|
126
|
+
|
|
127
|
+
- **Actions** — each public action is displayed as a pill, with RESTful actions (index, show, new, create, edit, update, destroy) getting a CRUD badge and tooltip description.
|
|
128
|
+
- **Unrouted action warnings** — actions without a matching route get an amber "No route" badge. If the action is a template method routed via child controllers, it shows "Routed via ChildController" instead.
|
|
129
|
+
- **Callbacks** — `before_action`, `after_action`, and `around_action` with full metadata:
|
|
130
|
+
- `only:` and `except:` restrictions
|
|
131
|
+
- `if:` and `unless:` conditions
|
|
132
|
+
- Inherited callback tracking (shows which parent class defined it)
|
|
133
|
+
- Custom Proc condition indicator
|
|
134
|
+
- **Public helpers** — non-routable public methods (ending in `?` or `=`) that might need visibility changes.
|
|
135
|
+
- **Superclass** shown for each controller.
|
|
136
|
+
- **Issues only** toggle to filter down to controllers with unrouted actions.
|
|
137
|
+
|
|
138
|
+
### Models
|
|
139
|
+
|
|
140
|
+
The richest tab, with two view modes:
|
|
141
|
+
|
|
142
|
+
#### List View
|
|
143
|
+
|
|
144
|
+
A namespace-grouped tree of all ActiveRecord models. Click any model to open a detail sidebar showing:
|
|
145
|
+
|
|
146
|
+
- **Columns** — name, type, nullability, default value, index info, and enum values.
|
|
147
|
+
- **Associations** — `has_many`, `belongs_to`, `has_one`, `has_many :through`, and `has_and_belongs_to_many` with class name, foreign key, `dependent:`, `as:` (polymorphic), and `through:` details.
|
|
148
|
+
- **Validations** — each validator with its kind, attributes, options, and validator class.
|
|
149
|
+
- **Enums** — enum name and all possible values.
|
|
150
|
+
- **Scopes** — named scopes defined in the model file.
|
|
151
|
+
- **Callbacks** — lifecycle callbacks (`before_save`, `after_create`, `around_destroy`, etc.) with the owning module/concern if inherited.
|
|
152
|
+
|
|
153
|
+
#### Canvas View (ER Diagram)
|
|
154
|
+
|
|
155
|
+
An interactive **React Flow** canvas that renders your schema as an entity-relationship diagram:
|
|
156
|
+
|
|
157
|
+
- **Model nodes** — cards showing the model name and its columns with types and constraints.
|
|
158
|
+
- **Association edges** — labeled, color-coded lines between related models.
|
|
159
|
+
- **Automatic layout** — powered by Dagre for clean graph arrangement.
|
|
160
|
+
- **Zoom, pan, and minimap** — navigate large schemas with ease.
|
|
161
|
+
- **Click-to-select** — click any model node to open the detail sidebar.
|
|
162
|
+
|
|
163
|
+
Both views support:
|
|
164
|
+
|
|
165
|
+
- **Search** — filter models by name or table name.
|
|
166
|
+
- **Issues only toggle** — filter to models without any validations.
|
|
167
|
+
|
|
168
|
+
### Migrations
|
|
169
|
+
|
|
170
|
+
Lists every migration file in `db/migrate/`:
|
|
171
|
+
|
|
172
|
+
- **Status** — green "Applied" badge or red "Pending" badge.
|
|
173
|
+
- **Human-readable name** — e.g. "Create Users" from `20240101_create_users.rb`.
|
|
174
|
+
- **Version timestamp** — parsed into a readable date.
|
|
175
|
+
- **Current version** indicator on the latest applied migration.
|
|
176
|
+
- **Filter** — by status (Applied, Pending) and search by name or version.
|
|
177
|
+
- **Open in editor** button for each migration file.
|
|
178
|
+
|
|
179
|
+
### Jobs
|
|
180
|
+
|
|
181
|
+
Covers both **ActiveJob** classes and **Sidekiq** workers:
|
|
182
|
+
|
|
183
|
+
- **Namespace tree** — jobs grouped by `::` module separators into a collapsible tree.
|
|
184
|
+
- **Queue** — color-coded badge per queue name.
|
|
185
|
+
- **ActiveJob details** — queue name, priority, `retry_on` handlers, and `discard_on` configuration.
|
|
186
|
+
- **Sidekiq details** — queue, retry setting, and uniqueness configuration. Workers with retries disabled get an amber warning.
|
|
187
|
+
- **Adapter info** — shows the configured queue adapter (Sidekiq, GoodJob, Solid Queue, etc.) with a description.
|
|
188
|
+
- **Filter** — by queue name, and an "Issues only" toggle for Sidekiq workers with retries disabled.
|
|
189
|
+
|
|
190
|
+
### Mailers
|
|
191
|
+
|
|
192
|
+
Namespace tree of all ActionMailer classes:
|
|
193
|
+
|
|
194
|
+
- **Email actions** — each mailer method displayed as a pill.
|
|
195
|
+
- **Inherited actions** — collapsible section showing email methods inherited from parent mailers, grouped by the defining class.
|
|
196
|
+
- **Default from** — the configured `default from:` address. Mailers without one are flagged.
|
|
197
|
+
- **Default reply-to** — if configured.
|
|
198
|
+
- **Layout** — the mailer layout name.
|
|
199
|
+
- **Callbacks** — `before_action`, `after_action`, and `around_action` on the mailer.
|
|
200
|
+
- **Abstract detection** — mailers with no own email methods that serve as base classes are marked as abstract.
|
|
201
|
+
- **Issues only** toggle to filter to mailers without a `default_from`.
|
|
202
|
+
|
|
203
|
+
## Configuration
|
|
204
|
+
|
|
205
|
+
Create an initializer to customize any defaults. All settings are optional:
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
# config/initializers/rails_visualizer.rb
|
|
209
|
+
RailsVisualizer.configure do |config|
|
|
210
|
+
# Exclude specific model class names from introspection.
|
|
211
|
+
# Useful for internal/legacy models you don't want in the dashboard.
|
|
212
|
+
config.excluded_models = ['AuditLog', 'InternalSession']
|
|
213
|
+
|
|
214
|
+
# Exclude specific controller class names.
|
|
215
|
+
config.excluded_controllers = ['HealthCheckController', 'Admin::InternalController']
|
|
216
|
+
|
|
217
|
+
# Exclude specific job class names.
|
|
218
|
+
config.excluded_jobs = ['LegacyCleanupJob']
|
|
219
|
+
|
|
220
|
+
# Exclude specific mailer class names.
|
|
221
|
+
config.excluded_mailers = ['InternalNotifier']
|
|
222
|
+
|
|
223
|
+
# Exclude routes whose paths start with these prefixes.
|
|
224
|
+
# Handy for mounted engines like Sidekiq Web or ActiveAdmin.
|
|
225
|
+
config.excluded_route_paths = ['/admin', '/sidekiq']
|
|
226
|
+
|
|
227
|
+
# Directory where the HTML file is written (relative to Rails.root).
|
|
228
|
+
config.output_path = 'tmp/rails_visualizer'
|
|
229
|
+
|
|
230
|
+
# Output filename.
|
|
231
|
+
config.filename = 'index.html'
|
|
232
|
+
|
|
233
|
+
# Automatically open the browser after generation. Set to false for CI or scripts.
|
|
234
|
+
config.open_browser = true
|
|
235
|
+
|
|
236
|
+
# Default color theme for the dashboard. Users can change it in the UI.
|
|
237
|
+
# :light or :dark
|
|
238
|
+
config.theme = :light
|
|
239
|
+
|
|
240
|
+
# Use fork-based parallel workers for model inspection on large apps.
|
|
241
|
+
# Disable if forking causes issues with your database driver or environment.
|
|
242
|
+
config.parallel = true
|
|
243
|
+
end
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Configuration Options Reference
|
|
247
|
+
|
|
248
|
+
| Option | Type | Default | Description |
|
|
249
|
+
|--------|------|---------|-------------|
|
|
250
|
+
| `excluded_models` | `Array<String>` | `[]` | Model class names to exclude |
|
|
251
|
+
| `excluded_controllers` | `Array<String>` | `[]` | Controller class names to exclude |
|
|
252
|
+
| `excluded_jobs` | `Array<String>` | `[]` | Job class names to exclude |
|
|
253
|
+
| `excluded_mailers` | `Array<String>` | `[]` | Mailer class names to exclude |
|
|
254
|
+
| `excluded_route_paths` | `Array<String>` | `[]` | Route path prefixes to exclude |
|
|
255
|
+
| `output_path` | `String` | `'tmp/rails_visualizer'` | Output directory (relative to `Rails.root`) |
|
|
256
|
+
| `filename` | `String` | `'index.html'` | Output file name |
|
|
257
|
+
| `open_browser` | `Boolean` | `true` | Auto-open browser after generation |
|
|
258
|
+
| `theme` | `Symbol` | `:light` | Default theme (`:light` or `:dark`) |
|
|
259
|
+
| `parallel` | `Boolean` | `true` | Enable fork-based parallel model inspection |
|
|
260
|
+
|
|
261
|
+
### Disabling Browser Auto-Open
|
|
262
|
+
|
|
263
|
+
If you're running in CI, scripting, or just want the file without opening a browser:
|
|
264
|
+
|
|
265
|
+
```ruby
|
|
266
|
+
RailsVisualizer.configure do |config|
|
|
267
|
+
config.open_browser = false
|
|
268
|
+
end
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Excluding Mounted Engine Routes
|
|
272
|
+
|
|
273
|
+
Many apps mount engines like Sidekiq Web, ActiveAdmin, or Letter Opener that add many routes you may not want to visualize:
|
|
274
|
+
|
|
275
|
+
```ruby
|
|
276
|
+
RailsVisualizer.configure do |config|
|
|
277
|
+
config.excluded_route_paths = ['/admin', '/sidekiq', '/letter_opener']
|
|
278
|
+
end
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Health Checks
|
|
282
|
+
|
|
283
|
+
The Overview tab runs automated health checks across your application and surfaces issues at a glance. Each check has a severity level:
|
|
284
|
+
|
|
285
|
+
| Check | Severity | Passes when |
|
|
286
|
+
|-------|----------|-------------|
|
|
287
|
+
| **Orphaned routes** | Error | All routes point to a known controller class |
|
|
288
|
+
| **Unrouted actions** | Warning | All public controller actions have a matching route |
|
|
289
|
+
| **Models without validations** | Warning | All models have at least one validation |
|
|
290
|
+
| **Pending migrations** | Error | All migrations have been applied |
|
|
291
|
+
| **Sidekiq retries disabled** | Warning | All Sidekiq workers have retries enabled |
|
|
292
|
+
| **Mailers without default_from** | Warning | All mailers have a `default from:` address |
|
|
293
|
+
|
|
294
|
+
Each failing check has a **"Go to"** button that navigates to the relevant tab where you can see the full details.
|
|
295
|
+
|
|
296
|
+
## How It Works
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
Rake task
|
|
300
|
+
└─ Introspector
|
|
301
|
+
├─ eager_load! (load all classes)
|
|
302
|
+
├─ 5 parallel Threads (routes, controllers, jobs, mailers, gems)
|
|
303
|
+
├─ Schema::Cache (bulk DB metadata in 2 SQL queries on PG)
|
|
304
|
+
├─ MigrationsInspector
|
|
305
|
+
└─ ModelInspector (fork-based workers for 50+ models)
|
|
306
|
+
└─ per-model: columns, associations, validations, enums, scopes, callbacks
|
|
307
|
+
└─ Serializer (Ruby Hash → camelCase JSON)
|
|
308
|
+
└─ Renderer (inject JSON into pre-built React HTML)
|
|
309
|
+
└─ Write tmp/rails_visualizer/index.html
|
|
310
|
+
└─ Open browser
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Step by Step
|
|
314
|
+
|
|
315
|
+
1. **Eager-load** — `Rails.application.eager_load!` ensures all classes are defined before introspection begins.
|
|
316
|
+
|
|
317
|
+
2. **Parallel introspection** — five inspectors run in parallel threads: `RoutesInspector`, `ControllersInspector`, `JobsInspector`, `MailersInspector`, and `GemsInspector`. Since these are I/O-bound (filesystem reads, route table traversal), threads give a meaningful speedup even with the GIL.
|
|
318
|
+
|
|
319
|
+
3. **Database metadata** — `Schema::Cache` bulk-loads all column and index metadata. On PostgreSQL, this runs **two parallel SQL queries** against `information_schema.columns` and `pg_index` with a SQL-level table filter for maximum speed. Other adapters use a per-table fallback through the ActiveRecord API.
|
|
320
|
+
|
|
321
|
+
4. **Model inspection** — `Schema::ModelInspector` inspects each model for columns, associations, validations, enums, scopes, and callbacks. On large apps (50+ models), inspection runs in **fork-based parallel workers** (up to 8 processes) for significant speedup on multi-core machines. Results are passed back via `Marshal.dump`/`load` through temp files.
|
|
322
|
+
|
|
323
|
+
5. **Serialization** — `Serializer` converts the Ruby hash to JSON, recursively transforming all `snake_case` keys to `camelCase` with memoized key conversion.
|
|
324
|
+
|
|
325
|
+
6. **Rendering** — `Renderer` reads the pre-built React HTML template and injects the JSON via a placeholder `<script>` tag, producing a single self-contained HTML file.
|
|
326
|
+
|
|
327
|
+
7. **Output** — the file is written to disk and optionally opened in the browser.
|
|
328
|
+
|
|
329
|
+
### Error Resilience
|
|
330
|
+
|
|
331
|
+
Every inspector follows the same safety pattern:
|
|
332
|
+
|
|
333
|
+
```ruby
|
|
334
|
+
def call
|
|
335
|
+
# ... introspection logic
|
|
336
|
+
rescue StandardError
|
|
337
|
+
[] # safe default — never crash the host app
|
|
338
|
+
end
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Individual model/controller/job failures are caught and skipped. Warnings are printed via `warn "[RailsVisualizer] ..."` but never raise.
|
|
342
|
+
|
|
343
|
+
## Performance
|
|
344
|
+
|
|
345
|
+
RailsVisualizer is designed to be fast even on large codebases:
|
|
346
|
+
|
|
347
|
+
- **Parallel threads** for I/O-bound inspectors (routes, controllers, jobs, mailers, gems).
|
|
348
|
+
- **Fork-based workers** for CPU-bound model inspection when you have 50+ models (automatically scales up to 8 processes based on CPU count).
|
|
349
|
+
- **Bulk SQL** on PostgreSQL — two queries total for all column and index metadata, instead of per-table queries.
|
|
350
|
+
- **Shared caches** — file content, method source locations, and enum lookups are cached across models to avoid redundant work.
|
|
351
|
+
- **Memoized key conversion** — the Serializer reuses the same ~30 camelCase key transforms across thousands of objects.
|
|
352
|
+
|
|
353
|
+
If you experience issues with fork-based parallelism (e.g. database driver compatibility), disable it:
|
|
354
|
+
|
|
355
|
+
```ruby
|
|
356
|
+
RailsVisualizer.configure do |config|
|
|
357
|
+
config.parallel = false
|
|
358
|
+
end
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## Compatibility
|
|
362
|
+
|
|
363
|
+
- **Ruby** >= 3.0
|
|
364
|
+
- **Rails** >= 7.0 (tested on 7.0, 7.1, 7.2, 8.0+)
|
|
365
|
+
- **PostgreSQL** — optimized with bulk-loaded parallel SQL queries for maximum speed
|
|
366
|
+
- **MySQL** — full support via per-table ActiveRecord API fallback
|
|
367
|
+
- **SQLite** — full support via per-table ActiveRecord API fallback
|
|
368
|
+
- **Any other ActiveRecord adapter** — per-table fallback with identical output
|
|
369
|
+
- **Zero runtime dependencies** — the gem adds nothing to your production bundle
|
|
370
|
+
- **ActionController::API** — API-only apps are fully supported alongside traditional apps
|
|
371
|
+
- **Sidekiq** — Sidekiq workers are detected alongside ActiveJob classes
|
|
372
|
+
|
|
373
|
+
## FAQ
|
|
374
|
+
|
|
375
|
+
**Does this affect my production app?**
|
|
376
|
+
No. The gem should be in the `:development` group and is only activated when you explicitly run the Rake task.
|
|
377
|
+
|
|
378
|
+
**Do I need Node.js?**
|
|
379
|
+
No. The frontend is pre-built into a single HTML file and committed to the gem. End users never need Node.js.
|
|
380
|
+
|
|
381
|
+
**Can I share the generated HTML file?**
|
|
382
|
+
Yes. The file is completely self-contained — all JavaScript, CSS, and data are inlined. Drop it in Slack, attach it to a PR, or email it. It works offline on any machine with a browser.
|
|
383
|
+
|
|
384
|
+
**Does it work with API-only Rails apps?**
|
|
385
|
+
Yes. Both `ActionController::Base` and `ActionController::API` controllers are introspected.
|
|
386
|
+
|
|
387
|
+
**What about STI / abstract models?**
|
|
388
|
+
Abstract models are excluded from introspection by default. STI models are included and shown with their own columns and associations.
|
|
389
|
+
|
|
390
|
+
**My app has 500+ models — will it be slow?**
|
|
391
|
+
The gem automatically uses fork-based parallel workers for large apps (50+ models, up to 8 workers). PostgreSQL users benefit from bulk SQL queries. A 500-model app typically generates in under 10 seconds.
|
|
392
|
+
|
|
393
|
+
**Can I customize the output path?**
|
|
394
|
+
Yes. See the [Configuration](#configuration) section. You can change both the directory and filename.
|
|
395
|
+
|
|
396
|
+
**The browser didn't open automatically.**
|
|
397
|
+
Set `config.open_browser = true` (the default) and make sure your system has a default browser configured. On Linux, the `open` command is replaced by `xdg-open` — if that's not working, set `open_browser` to false and open the file manually.
|
|
398
|
+
|
|
399
|
+
**How do I regenerate after code changes?**
|
|
400
|
+
Just run `bundle exec rake rails_visualizer` again. The file is overwritten each time.
|
|
401
|
+
|
|
402
|
+
**Does it detect issues?**
|
|
403
|
+
Yes. The Overview tab includes health checks for orphaned routes, unrouted controller actions, models without validations, pending migrations, Sidekiq workers with retries disabled, and mailers without a `default_from`. See [Health Checks](#health-checks).
|
|
404
|
+
|
|
405
|
+
## Development
|
|
406
|
+
|
|
407
|
+
Clone the repo and install dependencies:
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
git clone https://github.com/rajkamallashkari/rails_visualizer.git
|
|
411
|
+
cd rails_visualizer
|
|
412
|
+
bundle install
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Running Tests
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
bundle exec rspec
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
The test suite boots a minimal dummy Rails app with an in-memory SQLite database, so no external database is needed.
|
|
422
|
+
|
|
423
|
+
### Running RuboCop
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
bundle exec rubocop
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Frontend Development
|
|
430
|
+
|
|
431
|
+
The frontend is a Vite + React 18 + TypeScript + Tailwind CSS app. To work on it:
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
cd frontend
|
|
435
|
+
npm install
|
|
436
|
+
npm run dev # Start Vite dev server with hot reload
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
During frontend development, the app renders with an empty data payload. To test with real data, generate a dashboard from a Rails app and copy the JSON payload from the resulting HTML.
|
|
440
|
+
|
|
441
|
+
### Building the Frontend
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
cd frontend
|
|
445
|
+
npm run build
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
This builds a single self-contained HTML file (via `vite-plugin-singlefile`) to `lib/rails_visualizer/assets/dist/index.html`. This built file is committed to the repository so end users never need Node.js.
|
|
449
|
+
|
|
450
|
+
### Project Structure
|
|
451
|
+
|
|
452
|
+
```
|
|
453
|
+
lib/
|
|
454
|
+
rails_visualizer.rb # Entry point
|
|
455
|
+
rails_visualizer/
|
|
456
|
+
version.rb # VERSION constant
|
|
457
|
+
configuration.rb # All configurable options
|
|
458
|
+
railtie.rb # Loads rake task into Rails
|
|
459
|
+
path_helper.rb # Shared source file path resolution
|
|
460
|
+
introspector.rb # Orchestrator: parallel + fork-based
|
|
461
|
+
routes_inspector.rb # Route introspection
|
|
462
|
+
controllers_inspector.rb # Controller introspection
|
|
463
|
+
jobs_inspector.rb # ActiveJob + Sidekiq introspection
|
|
464
|
+
mailers_inspector.rb # Mailer introspection
|
|
465
|
+
migrations_inspector.rb # Migration status introspection
|
|
466
|
+
gems_inspector.rb # Bundler dependency introspection
|
|
467
|
+
serializer.rb # Ruby Hash → camelCase JSON
|
|
468
|
+
renderer.rb # JSON injection into HTML template
|
|
469
|
+
schema/
|
|
470
|
+
cache.rb # Bulk DB metadata (PG-optimized)
|
|
471
|
+
index_inspector.rb # Per-model index lookup
|
|
472
|
+
model_inspector.rb # Full model introspection
|
|
473
|
+
assets/dist/index.html # Pre-built frontend (committed)
|
|
474
|
+
tasks/
|
|
475
|
+
rails_visualizer.rake # The rake task
|
|
476
|
+
|
|
477
|
+
frontend/ # React source (dev only, not shipped)
|
|
478
|
+
src/
|
|
479
|
+
main.tsx # App bootstrap
|
|
480
|
+
App.tsx # Tab bar + tab routing
|
|
481
|
+
types.ts # TypeScript interfaces
|
|
482
|
+
hooks/useTheme.ts # Theme persistence
|
|
483
|
+
components/ # One component per tab + shared UI
|
|
484
|
+
utils/ # Layout, search, tree, dead code detection
|
|
485
|
+
|
|
486
|
+
spec/ # RSpec test suite
|
|
487
|
+
dummy/ # Minimal Rails app for testing
|
|
488
|
+
rails_visualizer/ # Inspector specs
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
## Contributing
|
|
492
|
+
|
|
493
|
+
1. Fork the repository.
|
|
494
|
+
2. Create a feature branch (`git checkout -b feature/my-feature`).
|
|
495
|
+
3. Make your changes with full test coverage and no RuboCop offenses.
|
|
496
|
+
4. Run the test suite and linter:
|
|
497
|
+
|
|
498
|
+
```bash
|
|
499
|
+
bundle exec rspec
|
|
500
|
+
bundle exec rubocop
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
5. Open a pull request.
|
|
504
|
+
|
|
505
|
+
Please keep each PR focused. Bug fixes and well-scoped features are most likely to be merged quickly.
|
|
506
|
+
|
|
507
|
+
## License
|
|
508
|
+
|
|
509
|
+
[MIT License](LICENSE.txt) © 2026 Raj Kamal Lashkari
|