rails_map 1.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/.idea/.gitignore +8 -0
- data/.idea/material_theme_project_new.xml +12 -0
- data/AUTHENTICATION.md +221 -0
- data/CHANGELOG.md +75 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/QUICKSTART.md +156 -0
- data/README.md +178 -0
- data/Rakefile +8 -0
- data/app/controllers/rails_map/docs_controller.rb +73 -0
- data/app/models/rails_map/user.rb +12 -0
- data/app/views/rails_map/docs/_styles.html.erb +489 -0
- data/app/views/rails_map/docs/controller.html.erb +137 -0
- data/app/views/rails_map/docs/index.html.erb +212 -0
- data/app/views/rails_map/docs/model.html.erb +214 -0
- data/app/views/rails_map/docs/routes.html.erb +139 -0
- data/config/initializers/rails_map.example.rb +44 -0
- data/config/routes.rb +9 -0
- data/docs/index.html +1354 -0
- data/lib/generators/rails_map/install_generator.rb +49 -0
- data/lib/generators/rails_map/templates/README +47 -0
- data/lib/generators/rails_map/templates/initializer.rb +38 -0
- data/lib/generators/rails_map/templates/migration.rb +14 -0
- data/lib/rails_map/auth.rb +15 -0
- data/lib/rails_map/configuration.rb +35 -0
- data/lib/rails_map/engine.rb +11 -0
- data/lib/rails_map/generators/html_generator.rb +120 -0
- data/lib/rails_map/parsers/model_parser.rb +257 -0
- data/lib/rails_map/parsers/route_parser.rb +356 -0
- data/lib/rails_map/railtie.rb +46 -0
- data/lib/rails_map/version.rb +5 -0
- data/lib/rails_map.rb +66 -0
- data/templates/controller.html.erb +74 -0
- data/templates/index.html.erb +64 -0
- data/templates/layout.html.erb +289 -0
- data/templates/model.html.erb +219 -0
- data/templates/routes.html.erb +86 -0
- metadata +144 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>API Documentation - <%= @config.app_name %></title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
10
|
+
<%= render partial: 'rails_map/docs/styles' %>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<header class="header">
|
|
14
|
+
<div class="container">
|
|
15
|
+
<div class="header-content">
|
|
16
|
+
<div>
|
|
17
|
+
<h1><%= @config.app_name %></h1>
|
|
18
|
+
<p class="subtitle">API Documentation</p>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="header-badge">
|
|
21
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
22
|
+
<circle cx="12" cy="12" r="10"/>
|
|
23
|
+
<polyline points="12,6 12,12 16,14"/>
|
|
24
|
+
</svg>
|
|
25
|
+
Auto-generated
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</header>
|
|
30
|
+
|
|
31
|
+
<main class="container">
|
|
32
|
+
<div class="stats-grid">
|
|
33
|
+
<div class="stat-card">
|
|
34
|
+
<div class="stat-value"><%= (@routes || {}).size %></div>
|
|
35
|
+
<div class="stat-label">Controllers</div>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="stat-card">
|
|
38
|
+
<div class="stat-value"><%= (@routes || {}).values.sum { |d| d[:routes]&.size || 0 } %></div>
|
|
39
|
+
<div class="stat-label">Routes</div>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="stat-card">
|
|
42
|
+
<div class="stat-value"><%= (@models || {}).size %></div>
|
|
43
|
+
<div class="stat-label">Models</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<div class="search-wrapper">
|
|
48
|
+
<svg class="search-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
49
|
+
<circle cx="11" cy="11" r="8"/>
|
|
50
|
+
<path d="m21 21-4.35-4.35"/>
|
|
51
|
+
</svg>
|
|
52
|
+
<input type="text" id="search-input" class="search-input" placeholder="Search controllers and models...">
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<div class="nav">
|
|
56
|
+
<%= link_to rails_map.routes_path do %>
|
|
57
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
58
|
+
<path d="M18 10h-4V6"/>
|
|
59
|
+
<path d="M14 10 21 3"/>
|
|
60
|
+
<path d="M21 14v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5"/>
|
|
61
|
+
</svg>
|
|
62
|
+
View All Routes
|
|
63
|
+
<% end %>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<section class="section" id="controllers-section">
|
|
67
|
+
<h2 class="section-header">
|
|
68
|
+
Controllers
|
|
69
|
+
<span class="section-count"><%= (@routes || {}).size %></span>
|
|
70
|
+
</h2>
|
|
71
|
+
<% if (@routes || {}).any? %>
|
|
72
|
+
<div class="grid">
|
|
73
|
+
<% (@routes || {}).each do |controller, data| %>
|
|
74
|
+
<div class="card" data-searchable="<%= controller.downcase %>">
|
|
75
|
+
<div class="card-header">
|
|
76
|
+
<h3 class="card-title" title="<%= controller.camelize %>Controller"><%= controller.camelize %></h3>
|
|
77
|
+
<span class="badge badge-count"><%= data[:routes].size %> routes</span>
|
|
78
|
+
</div>
|
|
79
|
+
<div class="card-meta">
|
|
80
|
+
<div class="card-meta-item">
|
|
81
|
+
<span class="card-meta-label">Base Path</span>
|
|
82
|
+
<code class="card-meta-value"><%= data[:base_path] || '/' %></code>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="card-stats">
|
|
86
|
+
<div class="card-stat">
|
|
87
|
+
<span class="card-stat-value"><%= data[:actions].size %></span>
|
|
88
|
+
<span class="card-stat-label">Actions</span>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="card-stat">
|
|
91
|
+
<span class="card-stat-value"><%= data[:routes].size %></span>
|
|
92
|
+
<span class="card-stat-label">Endpoints</span>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="card-footer">
|
|
96
|
+
<span class="card-actions"><%= data[:actions][0..2].join(', ') %><%= data[:actions].size > 3 ? '...' : '' %></span>
|
|
97
|
+
<%= link_to rails_map.controller_doc_path(name: controller), class: "card-link" do %>
|
|
98
|
+
View
|
|
99
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
100
|
+
<path d="M5 12h14"/>
|
|
101
|
+
<path d="m12 5 7 7-7 7"/>
|
|
102
|
+
</svg>
|
|
103
|
+
<% end %>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
<% end %>
|
|
107
|
+
</div>
|
|
108
|
+
<% else %>
|
|
109
|
+
<div class="empty-state">
|
|
110
|
+
<div class="empty-state-icon">📂</div>
|
|
111
|
+
<p>No controllers found</p>
|
|
112
|
+
</div>
|
|
113
|
+
<% end %>
|
|
114
|
+
</section>
|
|
115
|
+
|
|
116
|
+
<section class="section" id="models-section">
|
|
117
|
+
<h2 class="section-header">
|
|
118
|
+
Models
|
|
119
|
+
<span class="section-count"><%= (@models || {}).size %></span>
|
|
120
|
+
</h2>
|
|
121
|
+
<% if (@models || {}).any? %>
|
|
122
|
+
<div class="grid">
|
|
123
|
+
<% (@models || {}).each do |name, model| %>
|
|
124
|
+
<div class="card" data-searchable="<%= name.downcase %>">
|
|
125
|
+
<div class="card-header">
|
|
126
|
+
<h3 class="card-title" title="<%= name %>"><%= name %></h3>
|
|
127
|
+
<span class="badge badge-count"><%= model.columns.size %> cols</span>
|
|
128
|
+
</div>
|
|
129
|
+
<div class="card-meta">
|
|
130
|
+
<div class="card-meta-item">
|
|
131
|
+
<span class="card-meta-label">Table</span>
|
|
132
|
+
<code class="card-meta-value"><%= model.table_name || 'N/A' %></code>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="card-stats">
|
|
136
|
+
<div class="card-stat">
|
|
137
|
+
<span class="card-stat-value"><%= model.columns.size %></span>
|
|
138
|
+
<span class="card-stat-label">Columns</span>
|
|
139
|
+
</div>
|
|
140
|
+
<div class="card-stat">
|
|
141
|
+
<span class="card-stat-value"><%= model.associations.size %></span>
|
|
142
|
+
<span class="card-stat-label">Relations</span>
|
|
143
|
+
</div>
|
|
144
|
+
<% if model.validations.any? %>
|
|
145
|
+
<div class="card-stat">
|
|
146
|
+
<span class="card-stat-value"><%= model.validations.size %></span>
|
|
147
|
+
<span class="card-stat-label">Validations</span>
|
|
148
|
+
</div>
|
|
149
|
+
<% end %>
|
|
150
|
+
</div>
|
|
151
|
+
<div class="card-footer">
|
|
152
|
+
<span class="card-actions">pk: <%= model.primary_key || 'id' %></span>
|
|
153
|
+
<%= link_to rails_map.model_doc_path(name: name), class: "card-link" do %>
|
|
154
|
+
View
|
|
155
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
156
|
+
<path d="M5 12h14"/>
|
|
157
|
+
<path d="m12 5 7 7-7 7"/>
|
|
158
|
+
</svg>
|
|
159
|
+
<% end %>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
<% end %>
|
|
163
|
+
</div>
|
|
164
|
+
<% else %>
|
|
165
|
+
<div class="empty-state">
|
|
166
|
+
<div class="empty-state-icon">🗃️</div>
|
|
167
|
+
<p>No models found</p>
|
|
168
|
+
</div>
|
|
169
|
+
<% end %>
|
|
170
|
+
</section>
|
|
171
|
+
</main>
|
|
172
|
+
|
|
173
|
+
<footer class="footer">
|
|
174
|
+
<div>Generated by <a href="https://github.com/ArshdeepGrover/rails-map" target="_blank">RailsMap</a></div>
|
|
175
|
+
<div style="margin-top: 0.5rem;">Developed & maintained with ❤️ by <a href="https://www.arshdeepsingh.info?utm_source=rails_map&utm_medium=footer&utm_campaign=developer_credit&utm_content=docs_index" target="_blank">Arshdeep Singh</a></div>
|
|
176
|
+
</footer>
|
|
177
|
+
|
|
178
|
+
<script>
|
|
179
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
180
|
+
const searchInput = document.getElementById('search-input');
|
|
181
|
+
const cards = document.querySelectorAll('.card[data-searchable]');
|
|
182
|
+
const sections = document.querySelectorAll('.section');
|
|
183
|
+
|
|
184
|
+
searchInput.addEventListener('input', function() {
|
|
185
|
+
const query = this.value.toLowerCase().trim();
|
|
186
|
+
|
|
187
|
+
cards.forEach(function(card) {
|
|
188
|
+
const searchable = card.getAttribute('data-searchable');
|
|
189
|
+
if (query === '' || searchable.includes(query)) {
|
|
190
|
+
card.style.display = '';
|
|
191
|
+
card.style.opacity = '1';
|
|
192
|
+
} else {
|
|
193
|
+
card.style.display = 'none';
|
|
194
|
+
card.style.opacity = '0';
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Update section visibility
|
|
199
|
+
sections.forEach(function(section) {
|
|
200
|
+
const grid = section.querySelector('.grid');
|
|
201
|
+
const emptyState = section.querySelector('.empty-state');
|
|
202
|
+
if (grid) {
|
|
203
|
+
const visibleCards = grid.querySelectorAll('.card[data-searchable]:not([style*="display: none"])');
|
|
204
|
+
const hasVisible = visibleCards.length > 0;
|
|
205
|
+
section.style.display = hasVisible || query === '' ? '' : 'none';
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
</script>
|
|
211
|
+
</body>
|
|
212
|
+
</html>
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title><%= @model_name %> - <%= @config.app_name %></title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
10
|
+
<%= render partial: 'rails_map/docs/styles' %>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<header class="header">
|
|
14
|
+
<div class="container">
|
|
15
|
+
<div class="header-content">
|
|
16
|
+
<div>
|
|
17
|
+
<h1><%= @config.app_name %></h1>
|
|
18
|
+
<p class="subtitle">API Documentation</p>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</header>
|
|
23
|
+
|
|
24
|
+
<main class="container">
|
|
25
|
+
<div class="breadcrumb">
|
|
26
|
+
<%= link_to "Home", rails_map.root_path %>
|
|
27
|
+
<span class="breadcrumb-separator">/</span>
|
|
28
|
+
<span class="breadcrumb-current"><%= @model_name %></span>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="stats-grid" style="grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); margin-bottom: 2rem;">
|
|
32
|
+
<div class="stat-card">
|
|
33
|
+
<div class="stat-value"><%= @model.columns.size %></div>
|
|
34
|
+
<div class="stat-label">Columns</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="stat-card">
|
|
37
|
+
<div class="stat-value"><%= @model.associations.size %></div>
|
|
38
|
+
<div class="stat-label">Relations</div>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="stat-card">
|
|
41
|
+
<div class="stat-value"><%= @model.validations.size %></div>
|
|
42
|
+
<div class="stat-label">Validations</div>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="stat-card" style="text-align: left; padding: 1.25rem;">
|
|
45
|
+
<div class="stat-label" style="margin-bottom: 0.5rem;">Table</div>
|
|
46
|
+
<code style="font-size: 0.9rem;"><%= @model.table_name || 'N/A' %></code>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<!-- Columns -->
|
|
51
|
+
<section class="section">
|
|
52
|
+
<h2 class="section-header">
|
|
53
|
+
Columns
|
|
54
|
+
<span class="section-count"><%= @model.columns.size %></span>
|
|
55
|
+
</h2>
|
|
56
|
+
<% if @model.columns.any? %>
|
|
57
|
+
<div class="table-container">
|
|
58
|
+
<table>
|
|
59
|
+
<thead>
|
|
60
|
+
<tr>
|
|
61
|
+
<th>Name</th>
|
|
62
|
+
<th>Type</th>
|
|
63
|
+
<th>Nullable</th>
|
|
64
|
+
<th>Default</th>
|
|
65
|
+
</tr>
|
|
66
|
+
</thead>
|
|
67
|
+
<tbody>
|
|
68
|
+
<% @model.columns.each do |column| %>
|
|
69
|
+
<tr>
|
|
70
|
+
<td>
|
|
71
|
+
<code><%= column.name %></code>
|
|
72
|
+
<% if column.name == @model.primary_key %>
|
|
73
|
+
<span class="badge badge-post" style="margin-left: 0.5rem;">PK</span>
|
|
74
|
+
<% end %>
|
|
75
|
+
</td>
|
|
76
|
+
<td><span class="type-badge"><%= column.type %></span></td>
|
|
77
|
+
<td>
|
|
78
|
+
<% if column.null %>
|
|
79
|
+
<span style="color: #4ade80;">✓ Yes</span>
|
|
80
|
+
<% else %>
|
|
81
|
+
<span style="color: #f87171;">✗ No</span>
|
|
82
|
+
<% end %>
|
|
83
|
+
</td>
|
|
84
|
+
<td>
|
|
85
|
+
<% if column.default.nil? %>
|
|
86
|
+
<span style="color: var(--text-dim);">—</span>
|
|
87
|
+
<% else %>
|
|
88
|
+
<code><%= column.default %></code>
|
|
89
|
+
<% end %>
|
|
90
|
+
</td>
|
|
91
|
+
</tr>
|
|
92
|
+
<% end %>
|
|
93
|
+
</tbody>
|
|
94
|
+
</table>
|
|
95
|
+
</div>
|
|
96
|
+
<% else %>
|
|
97
|
+
<div class="empty-state">
|
|
98
|
+
<div class="empty-state-icon">📋</div>
|
|
99
|
+
<p>No columns found</p>
|
|
100
|
+
</div>
|
|
101
|
+
<% end %>
|
|
102
|
+
</section>
|
|
103
|
+
|
|
104
|
+
<!-- Associations -->
|
|
105
|
+
<section class="section">
|
|
106
|
+
<h2 class="section-header">
|
|
107
|
+
Associations
|
|
108
|
+
<span class="section-count"><%= @model.associations.size %></span>
|
|
109
|
+
</h2>
|
|
110
|
+
<% if @model.associations.any? %>
|
|
111
|
+
<div class="table-container">
|
|
112
|
+
<table>
|
|
113
|
+
<thead>
|
|
114
|
+
<tr>
|
|
115
|
+
<th>Type</th>
|
|
116
|
+
<th>Name</th>
|
|
117
|
+
<th>Related Model</th>
|
|
118
|
+
<th>Foreign Key</th>
|
|
119
|
+
</tr>
|
|
120
|
+
</thead>
|
|
121
|
+
<tbody>
|
|
122
|
+
<% @model.associations.each do |assoc| %>
|
|
123
|
+
<tr>
|
|
124
|
+
<td>
|
|
125
|
+
<span class="badge badge-<%= assoc.type.to_s.gsub('_', '-') %>">
|
|
126
|
+
<%= assoc.type.to_s.gsub('_', ' ') %>
|
|
127
|
+
</span>
|
|
128
|
+
</td>
|
|
129
|
+
<td><code><%= assoc.name %></code></td>
|
|
130
|
+
<td>
|
|
131
|
+
<%= link_to assoc.class_name, rails_map.model_doc_path(name: assoc.class_name), class: "link" %>
|
|
132
|
+
</td>
|
|
133
|
+
<td>
|
|
134
|
+
<% if assoc.foreign_key %>
|
|
135
|
+
<code><%= assoc.foreign_key %></code>
|
|
136
|
+
<% else %>
|
|
137
|
+
<span style="color: var(--text-dim);">—</span>
|
|
138
|
+
<% end %>
|
|
139
|
+
</td>
|
|
140
|
+
</tr>
|
|
141
|
+
<% end %>
|
|
142
|
+
</tbody>
|
|
143
|
+
</table>
|
|
144
|
+
</div>
|
|
145
|
+
<% else %>
|
|
146
|
+
<div class="empty-state">
|
|
147
|
+
<div class="empty-state-icon">🔗</div>
|
|
148
|
+
<p>No associations found</p>
|
|
149
|
+
</div>
|
|
150
|
+
<% end %>
|
|
151
|
+
</section>
|
|
152
|
+
|
|
153
|
+
<!-- Validations -->
|
|
154
|
+
<% if @model.validations.any? %>
|
|
155
|
+
<section class="section">
|
|
156
|
+
<h2 class="section-header">
|
|
157
|
+
Validations
|
|
158
|
+
<span class="section-count"><%= @model.validations.size %></span>
|
|
159
|
+
</h2>
|
|
160
|
+
<div class="table-container">
|
|
161
|
+
<table>
|
|
162
|
+
<thead>
|
|
163
|
+
<tr>
|
|
164
|
+
<th>Attribute</th>
|
|
165
|
+
<th>Validation</th>
|
|
166
|
+
<th>Options</th>
|
|
167
|
+
</tr>
|
|
168
|
+
</thead>
|
|
169
|
+
<tbody>
|
|
170
|
+
<% @model.validations.each do |validation| %>
|
|
171
|
+
<tr>
|
|
172
|
+
<td><code><%= validation.attribute %></code></td>
|
|
173
|
+
<td><span class="badge badge-count"><%= validation.kind %></span></td>
|
|
174
|
+
<td>
|
|
175
|
+
<% if validation.options.any? %>
|
|
176
|
+
<% validation.options.each do |key, value| %>
|
|
177
|
+
<code style="margin-right: 0.5rem;"><%= key %>: <%= value %></code>
|
|
178
|
+
<% end %>
|
|
179
|
+
<% else %>
|
|
180
|
+
<span style="color: var(--text-dim);">—</span>
|
|
181
|
+
<% end %>
|
|
182
|
+
</td>
|
|
183
|
+
</tr>
|
|
184
|
+
<% end %>
|
|
185
|
+
</tbody>
|
|
186
|
+
</table>
|
|
187
|
+
</div>
|
|
188
|
+
</section>
|
|
189
|
+
<% end %>
|
|
190
|
+
|
|
191
|
+
<!-- Scopes -->
|
|
192
|
+
<% if @model.scopes.any? %>
|
|
193
|
+
<section class="section">
|
|
194
|
+
<h2 class="section-header">
|
|
195
|
+
Scopes
|
|
196
|
+
<span class="section-count"><%= @model.scopes.size %></span>
|
|
197
|
+
</h2>
|
|
198
|
+
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem;">
|
|
199
|
+
<% @model.scopes.each do |scope| %>
|
|
200
|
+
<span class="badge badge-count" style="font-size: 0.8125rem; padding: 0.375rem 0.75rem;">
|
|
201
|
+
<%= scope.name %><%= scope.arity != 0 ? "(#{scope.arity > 0 ? scope.arity : '...'})" : '' %>
|
|
202
|
+
</span>
|
|
203
|
+
<% end %>
|
|
204
|
+
</div>
|
|
205
|
+
</section>
|
|
206
|
+
<% end %>
|
|
207
|
+
</main>
|
|
208
|
+
|
|
209
|
+
<footer class="footer">
|
|
210
|
+
<div>Generated by <a href="https://github.com/ArshdeepGrover/rails-map" target="_blank">RailsMap</a></div>
|
|
211
|
+
<div style="margin-top: 0.5rem;">Developed & maintained with ❤️ by <a href="https://www.arshdeepsingh.info?utm_source=rails_map&utm_medium=footer&utm_campaign=developer_credit&utm_content=docs_model" target="_blank">Arshdeep Singh</a></div>
|
|
212
|
+
</footer>
|
|
213
|
+
</body>
|
|
214
|
+
</html>
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>All Routes - <%= @config.app_name %></title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
10
|
+
<%= render partial: 'rails_map/docs/styles' %>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<header class="header">
|
|
14
|
+
<div class="container">
|
|
15
|
+
<div class="header-content">
|
|
16
|
+
<div>
|
|
17
|
+
<h1><%= @config.app_name %></h1>
|
|
18
|
+
<p class="subtitle">API Documentation</p>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</header>
|
|
23
|
+
|
|
24
|
+
<main class="container">
|
|
25
|
+
<div class="breadcrumb">
|
|
26
|
+
<%= link_to "Home", rails_map.root_path %>
|
|
27
|
+
<span class="breadcrumb-separator">/</span>
|
|
28
|
+
<span class="breadcrumb-current">All Routes</span>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="search-wrapper" style="margin-bottom: 1.5rem;">
|
|
32
|
+
<svg class="search-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
33
|
+
<circle cx="11" cy="11" r="8"/>
|
|
34
|
+
<path d="m21 21-4.35-4.35"/>
|
|
35
|
+
</svg>
|
|
36
|
+
<input type="text" id="route-search" class="search-input" placeholder="Search routes...">
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div class="table-container">
|
|
40
|
+
<table>
|
|
41
|
+
<thead>
|
|
42
|
+
<tr>
|
|
43
|
+
<th style="width: 100px;">Method</th>
|
|
44
|
+
<th>Path</th>
|
|
45
|
+
<th>Controller#Action</th>
|
|
46
|
+
<th>Parameters</th>
|
|
47
|
+
</tr>
|
|
48
|
+
</thead>
|
|
49
|
+
<tbody id="routes-table-body">
|
|
50
|
+
<% if (@routes || {}).any? %>
|
|
51
|
+
<% (@routes || {}).each do |controller, data| %>
|
|
52
|
+
<% data[:routes].each do |route| %>
|
|
53
|
+
<tr data-searchable="<%= route.path.downcase %> <%= controller.downcase %> <%= route.action.downcase %> <%= route.name&.downcase %>">
|
|
54
|
+
<td>
|
|
55
|
+
<span class="badge badge-<%= route.verb.to_s.downcase.split('|').first %>">
|
|
56
|
+
<%= route.verb %>
|
|
57
|
+
</span>
|
|
58
|
+
</td>
|
|
59
|
+
<td><code><%= route.path %></code></td>
|
|
60
|
+
<td>
|
|
61
|
+
<%= link_to "#{controller}##{route.action}", rails_map.controller_doc_path(name: controller), class: "link" %>
|
|
62
|
+
</td>
|
|
63
|
+
<td>
|
|
64
|
+
<% all_params = [] %>
|
|
65
|
+
<% all_params += route.path_params if route.path_params&.any? %>
|
|
66
|
+
<% verb = route.verb.to_s.upcase %>
|
|
67
|
+
<% if %w[GET DELETE].include?(verb) %>
|
|
68
|
+
<% all_params += route.query_params if route.query_params&.any? %>
|
|
69
|
+
<% elsif %w[POST PUT PATCH].include?(verb) %>
|
|
70
|
+
<% all_params += route.request_body_params if route.request_body_params&.any? %>
|
|
71
|
+
<% end %>
|
|
72
|
+
|
|
73
|
+
<% if all_params.any? %>
|
|
74
|
+
<details style="cursor: pointer;">
|
|
75
|
+
<summary style="color: var(--primary); font-weight: 500;">
|
|
76
|
+
<%= all_params.size %> parameter<%= all_params.size > 1 ? 's' : '' %>
|
|
77
|
+
</summary>
|
|
78
|
+
<div style="margin-top: 0.5rem; padding: 0.75rem; background: var(--bg-secondary); border-radius: 6px; font-size: 0.875rem;">
|
|
79
|
+
<% all_params.each do |param| %>
|
|
80
|
+
<div style="margin-bottom: 0.5rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--border);">
|
|
81
|
+
<div style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.25rem;">
|
|
82
|
+
<code style="font-weight: 600; color: var(--primary);"><%= param[:name] %></code>
|
|
83
|
+
<span class="badge" style="font-size: 0.75rem; padding: 0.125rem 0.375rem;"><%= param[:type] %></span>
|
|
84
|
+
<% if param[:required] %>
|
|
85
|
+
<span style="color: var(--danger); font-size: 0.75rem; font-weight: 600;">required</span>
|
|
86
|
+
<% else %>
|
|
87
|
+
<span style="color: var(--text-dim); font-size: 0.75rem;">optional</span>
|
|
88
|
+
<% end %>
|
|
89
|
+
</div>
|
|
90
|
+
<div style="color: var(--text-dim); font-size: 0.75rem;">
|
|
91
|
+
Location: <%= param[:location] %>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
<% end %>
|
|
95
|
+
</div>
|
|
96
|
+
</details>
|
|
97
|
+
<% else %>
|
|
98
|
+
<span style="color: var(--text-dim);">No parameters</span>
|
|
99
|
+
<% end %>
|
|
100
|
+
</td>
|
|
101
|
+
</tr>
|
|
102
|
+
<% end %>
|
|
103
|
+
<% end %>
|
|
104
|
+
<% else %>
|
|
105
|
+
<tr>
|
|
106
|
+
<td colspan="4" class="empty-state">No routes found</td>
|
|
107
|
+
</tr>
|
|
108
|
+
<% end %>
|
|
109
|
+
</tbody>
|
|
110
|
+
</table>
|
|
111
|
+
</div>
|
|
112
|
+
</main>
|
|
113
|
+
|
|
114
|
+
<footer class="footer">
|
|
115
|
+
<div>Generated by <a href="https://github.com/ArshdeepGrover/rails-map" target="_blank">RailsMap</a></div>
|
|
116
|
+
<div style="margin-top: 0.5rem;">Developed & maintained with ❤️ by <a href="https://www.arshdeepsingh.info?utm_source=rails_map&utm_medium=footer&utm_campaign=developer_credit&utm_content=docs_routes" target="_blank">Arshdeep Singh</a></div>
|
|
117
|
+
</footer>
|
|
118
|
+
|
|
119
|
+
<script>
|
|
120
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
121
|
+
const searchInput = document.getElementById('route-search');
|
|
122
|
+
const rows = document.querySelectorAll('#routes-table-body tr[data-searchable]');
|
|
123
|
+
|
|
124
|
+
searchInput.addEventListener('input', function() {
|
|
125
|
+
const query = this.value.toLowerCase().trim();
|
|
126
|
+
|
|
127
|
+
rows.forEach(function(row) {
|
|
128
|
+
const searchable = row.getAttribute('data-searchable');
|
|
129
|
+
if (query === '' || searchable.includes(query)) {
|
|
130
|
+
row.style.display = '';
|
|
131
|
+
} else {
|
|
132
|
+
row.style.display = 'none';
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
</script>
|
|
138
|
+
</body>
|
|
139
|
+
</html>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Example configuration for RailsMap
|
|
4
|
+
# Copy this file to your Rails application's config/initializers/rails_map.rb
|
|
5
|
+
|
|
6
|
+
RailsMap.configure do |config|
|
|
7
|
+
# Application name displayed in the documentation
|
|
8
|
+
config.app_name = 'My Application'
|
|
9
|
+
|
|
10
|
+
# Theme color (any valid CSS color)
|
|
11
|
+
config.theme_color = '#3B82F6'
|
|
12
|
+
|
|
13
|
+
# Output directory for static HTML generation
|
|
14
|
+
config.output_dir = Rails.root.join('doc', 'api').to_s
|
|
15
|
+
|
|
16
|
+
# Include timestamp columns (created_at, updated_at) in model documentation
|
|
17
|
+
config.include_timestamps = true
|
|
18
|
+
|
|
19
|
+
# Include model validations in documentation
|
|
20
|
+
config.include_validations = true
|
|
21
|
+
|
|
22
|
+
# Include model scopes in documentation
|
|
23
|
+
config.include_scopes = true
|
|
24
|
+
|
|
25
|
+
# ============================================================================
|
|
26
|
+
# AUTHENTICATION
|
|
27
|
+
# ============================================================================
|
|
28
|
+
# Set RAILS_MAP_USERNAME and RAILS_MAP_PASSWORD environment variables
|
|
29
|
+
# to enable authentication. Leave them unset for public access.
|
|
30
|
+
|
|
31
|
+
config.authenticate_with = proc {
|
|
32
|
+
RailsMap::Auth.authenticate(self)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# Alternative: Devise authentication
|
|
36
|
+
# config.authenticate_with = proc {
|
|
37
|
+
# authenticate_user!
|
|
38
|
+
# }
|
|
39
|
+
|
|
40
|
+
# Alternative: Custom logic
|
|
41
|
+
# config.authenticate_with = proc {
|
|
42
|
+
# redirect_to root_path unless current_user&.admin?
|
|
43
|
+
# }
|
|
44
|
+
end
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RailsMap::Engine.routes.draw do
|
|
4
|
+
root to: "docs#index"
|
|
5
|
+
|
|
6
|
+
get "routes", to: "docs#routes", as: :routes
|
|
7
|
+
get "controllers/*name", to: "docs#controller", as: :controller_doc
|
|
8
|
+
get "models/*name", to: "docs#model", as: :model_doc
|
|
9
|
+
end
|