dbviewer 0.5.0 → 0.5.2
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 +4 -4
- data/README.md +64 -1
- data/app/controllers/concerns/dbviewer/database_operations.rb +27 -45
- data/app/controllers/dbviewer/api/database_controller.rb +2 -6
- data/app/controllers/dbviewer/api/queries_controller.rb +18 -8
- data/app/controllers/dbviewer/api/tables_controller.rb +48 -23
- data/app/controllers/dbviewer/application_controller.rb +1 -1
- data/app/controllers/dbviewer/home_controller.rb +1 -1
- data/app/controllers/dbviewer/tables_controller.rb +2 -2
- data/app/views/dbviewer/home/index.html.erb +1 -1
- data/lib/dbviewer/database_manager.rb +40 -0
- data/lib/dbviewer/engine.rb +22 -4
- data/lib/dbviewer/logger.rb +1 -1
- data/lib/dbviewer/query_parser.rb +3 -32
- data/lib/dbviewer/version.rb +1 -1
- metadata +1 -2
- data/lib/generators/dbviewer/structured_api_generator.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fff65e39ec4f823de37b99cf4b60c49d998e56bf2ff10cde22e9d664ea193fdc
|
4
|
+
data.tar.gz: 3ad5a045ab31b37c8f8d7ae410499f9f16a9a10fe8a52a8b3161e331cb3f0f6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72f824b283bd82504319fe5002d48d1f8a7cd29f4038773d4e75ff7c8e9ba250e27de2239eee36adac6ff10740e5779a5272f0c202f2bb1ccb32c586f94ea093
|
7
|
+
data.tar.gz: 655d0bd7d9ea5fc5c70e338b8bdea8dd000b8fd25984c267243598a02afcaff50ba185d80d123b9e2203148b82945f13ebc47d470ef900252887cdfe4134d3c6
|
data/README.md
CHANGED
@@ -7,7 +7,6 @@ It's designed for development, debugging, and database analysis, offering a clea
|
|
7
7
|
|
8
8
|
<img width="1470" alt="image" src="https://github.com/user-attachments/assets/0d2719ad-f5b4-4818-891d-5bff7be6c5c3" />
|
9
9
|
|
10
|
-
|
11
10
|
## ✨ Features
|
12
11
|
|
13
12
|
- **Dashboard**: View a comprehensive dashboard with database analytics, largest tables, most complex tables, and recent SQL queries
|
@@ -270,6 +269,70 @@ The simplest way to update is using Bundler:
|
|
270
269
|
rails server
|
271
270
|
```
|
272
271
|
|
272
|
+
## 🛠️ Development Setup
|
273
|
+
|
274
|
+
To set up the development environment for contributing to DBViewer:
|
275
|
+
|
276
|
+
### Quick Setup
|
277
|
+
|
278
|
+
Run the setup script to automatically configure your development environment:
|
279
|
+
|
280
|
+
```bash
|
281
|
+
bin/setup
|
282
|
+
```
|
283
|
+
|
284
|
+
This script will:
|
285
|
+
|
286
|
+
- Install bundler and gem dependencies
|
287
|
+
- Set up the test dummy Rails application
|
288
|
+
- Create and seed the development database
|
289
|
+
- Prepare the test environment
|
290
|
+
- Clean up old logs and temporary files
|
291
|
+
|
292
|
+
### Manual Setup
|
293
|
+
|
294
|
+
If you prefer to set up manually:
|
295
|
+
|
296
|
+
```bash
|
297
|
+
# Install dependencies
|
298
|
+
bundle install
|
299
|
+
|
300
|
+
# Set up the dummy app database
|
301
|
+
cd test/dummy
|
302
|
+
bin/rails db:prepare
|
303
|
+
bin/rails db:migrate
|
304
|
+
bin/rails db:seed
|
305
|
+
cd ../..
|
306
|
+
|
307
|
+
# Prepare test environment
|
308
|
+
cd test/dummy && bin/rails db:test:prepare && cd ../..
|
309
|
+
```
|
310
|
+
|
311
|
+
### Development Commands
|
312
|
+
|
313
|
+
```bash
|
314
|
+
# Start the development server
|
315
|
+
cd test/dummy && bin/rails server
|
316
|
+
|
317
|
+
# Run tests
|
318
|
+
bundle exec rspec
|
319
|
+
|
320
|
+
# Run code quality checks
|
321
|
+
bin/rubocop
|
322
|
+
|
323
|
+
# Open an interactive console
|
324
|
+
bin/console
|
325
|
+
|
326
|
+
# Build the gem
|
327
|
+
gem build dbviewer.gemspec
|
328
|
+
```
|
329
|
+
|
330
|
+
### Testing Your Changes
|
331
|
+
|
332
|
+
1. Start the dummy Rails application: `cd test/dummy && bin/rails server`
|
333
|
+
2. Visit `http://localhost:3000/dbviewer` to test your changes
|
334
|
+
3. The dummy app includes sample data across multiple tables to test various DBViewer features
|
335
|
+
|
273
336
|
## 🤌🏻 Contributing
|
274
337
|
|
275
338
|
Bug reports and pull requests are welcome.
|
@@ -5,7 +5,7 @@ module Dbviewer
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
helper_method :current_table?, :get_database_name if respond_to?(:helper_method)
|
8
|
+
helper_method :current_table?, :get_database_name, :get_adapter_name if respond_to?(:helper_method)
|
9
9
|
end
|
10
10
|
|
11
11
|
# Initialize the database manager
|
@@ -44,9 +44,33 @@ module Dbviewer
|
|
44
44
|
"Database"
|
45
45
|
end
|
46
46
|
|
47
|
+
# Get the name of the current database adapter
|
48
|
+
def get_adapter_name
|
49
|
+
adapter = database_manager.connection.adapter_name
|
50
|
+
|
51
|
+
# Format the adapter name for better display
|
52
|
+
case adapter.downcase
|
53
|
+
when /mysql/
|
54
|
+
"MySQL"
|
55
|
+
when /postgres/
|
56
|
+
"PostgreSQL"
|
57
|
+
when /sqlite/
|
58
|
+
"SQLite"
|
59
|
+
when /oracle/
|
60
|
+
"Oracle"
|
61
|
+
when /sqlserver/, /mssql/
|
62
|
+
"SQL Server"
|
63
|
+
else
|
64
|
+
adapter.titleize # Fallback to titleized version
|
65
|
+
end
|
66
|
+
rescue => e
|
67
|
+
Rails.logger.error("Error retrieving adapter name: #{e.message}")
|
68
|
+
"Unknown"
|
69
|
+
end
|
70
|
+
|
47
71
|
# Fetch all tables with their stats
|
48
72
|
# By default, don't include record counts for better performance on sidebar
|
49
|
-
def
|
73
|
+
def fetch_tables(include_record_counts = false)
|
50
74
|
database_manager.tables.map do |table_name|
|
51
75
|
table_stats = {
|
52
76
|
name: table_name
|
@@ -62,7 +86,7 @@ module Dbviewer
|
|
62
86
|
# Gather database analytics information
|
63
87
|
def fetch_database_analytics
|
64
88
|
# For analytics, we do need record counts
|
65
|
-
tables =
|
89
|
+
tables = fetch_tables(include_record_counts: true)
|
66
90
|
|
67
91
|
# Calculate overall statistics
|
68
92
|
analytics = {
|
@@ -77,48 +101,6 @@ module Dbviewer
|
|
77
101
|
analytics
|
78
102
|
end
|
79
103
|
|
80
|
-
# Calculate approximate schema size
|
81
|
-
def calculate_schema_size
|
82
|
-
adapter = database_manager.connection.adapter_name.downcase
|
83
|
-
|
84
|
-
case adapter
|
85
|
-
when /mysql/
|
86
|
-
query = <<-SQL
|
87
|
-
SELECT
|
88
|
-
SUM(data_length + index_length) AS size
|
89
|
-
FROM
|
90
|
-
information_schema.TABLES
|
91
|
-
WHERE
|
92
|
-
table_schema = DATABASE()
|
93
|
-
SQL
|
94
|
-
result = database_manager.execute_query(query).first
|
95
|
-
result ? result["size"].to_i : nil
|
96
|
-
when /postgres/
|
97
|
-
query = <<-SQL
|
98
|
-
SELECT pg_database_size(current_database()) AS size
|
99
|
-
SQL
|
100
|
-
result = database_manager.execute_query(query).first
|
101
|
-
result ? result["size"].to_i : nil
|
102
|
-
when /sqlite/
|
103
|
-
# For SQLite, we need to use the special PRAGMA method without LIMIT
|
104
|
-
# Get page count
|
105
|
-
page_count_result = database_manager.execute_sqlite_pragma("page_count")
|
106
|
-
page_count = page_count_result.first.values.first.to_i
|
107
|
-
|
108
|
-
# Get page size
|
109
|
-
page_size_result = database_manager.execute_sqlite_pragma("page_size")
|
110
|
-
page_size = page_size_result.first.values.first.to_i
|
111
|
-
|
112
|
-
# Calculate total size
|
113
|
-
page_count * page_size
|
114
|
-
else
|
115
|
-
nil # Unsupported database type for size calculation
|
116
|
-
end
|
117
|
-
rescue => e
|
118
|
-
Rails.logger.error("Error calculating database size: #{e.message}")
|
119
|
-
nil
|
120
|
-
end
|
121
|
-
|
122
104
|
# Get column information for a specific table
|
123
105
|
def fetch_table_columns(table_name)
|
124
106
|
database_manager.table_columns(table_name)
|
@@ -2,12 +2,8 @@ module Dbviewer
|
|
2
2
|
module Api
|
3
3
|
class DatabaseController < BaseController
|
4
4
|
def size
|
5
|
-
|
6
|
-
|
7
|
-
render_success(schema_size: size)
|
8
|
-
rescue => e
|
9
|
-
render_error("Error calculating schema size: #{e.message}")
|
10
|
-
end
|
5
|
+
size = database_manager.fetch_schema_size
|
6
|
+
render_success(schema_size: size)
|
11
7
|
end
|
12
8
|
end
|
13
9
|
end
|
@@ -2,17 +2,27 @@ module Dbviewer
|
|
2
2
|
module Api
|
3
3
|
class QueriesController < BaseController
|
4
4
|
def recent
|
5
|
-
@recent_queries = if Dbviewer.configuration.enable_query_logging
|
6
|
-
Dbviewer::Logger.instance.recent_queries(limit: 10)
|
7
|
-
else
|
8
|
-
[]
|
9
|
-
end
|
10
|
-
|
11
5
|
render_success({
|
12
|
-
enabled:
|
13
|
-
queries:
|
6
|
+
enabled: query_logging_enabled?,
|
7
|
+
queries: fetch_recent_queries
|
14
8
|
})
|
15
9
|
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def fetch_recent_queries
|
14
|
+
return [] unless query_logging_enabled?
|
15
|
+
|
16
|
+
Dbviewer::Logger.instance.recent_queries(limit: queries_limit)
|
17
|
+
end
|
18
|
+
|
19
|
+
def query_logging_enabled?
|
20
|
+
Dbviewer.configuration.enable_query_logging
|
21
|
+
end
|
22
|
+
|
23
|
+
def queries_limit
|
24
|
+
10
|
25
|
+
end
|
16
26
|
end
|
17
27
|
end
|
18
28
|
end
|
@@ -2,38 +2,63 @@ module Dbviewer
|
|
2
2
|
module Api
|
3
3
|
class TablesController < BaseController
|
4
4
|
def index
|
5
|
-
|
6
|
-
render_success(total_tables:
|
5
|
+
tables_count = fetch_tables_count
|
6
|
+
render_success(total_tables: tables_count)
|
7
7
|
end
|
8
8
|
|
9
9
|
def records
|
10
|
-
|
10
|
+
tables_stats = fetch_tables_stats
|
11
|
+
render_success(tables_stats)
|
12
|
+
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
def relationships_count
|
15
|
+
total_relationships = calculate_total_relationships
|
16
|
+
render_success(total_relationships: total_relationships)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
18
20
|
|
19
|
-
|
21
|
+
def fetch_tables_count
|
22
|
+
fetch_tables(include_record_counts: false).size
|
20
23
|
end
|
21
24
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
tables
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
25
|
+
def fetch_tables_stats
|
26
|
+
tables = fetch_tables(include_record_counts: true)
|
27
|
+
|
28
|
+
{
|
29
|
+
total_records: calculate_total_records(tables),
|
30
|
+
largest_tables: find_largest_tables(tables),
|
31
|
+
empty_tables: find_empty_tables(tables),
|
32
|
+
avg_records_per_table: calculate_average_records(tables)
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def calculate_total_relationships
|
37
|
+
tables = fetch_tables(include_record_counts: false)
|
38
|
+
|
39
|
+
tables.sum do |table|
|
40
|
+
metadata = fetch_table_metadata(table[:name])
|
41
|
+
metadata&.dig(:foreign_keys)&.size || 0
|
35
42
|
end
|
36
43
|
end
|
44
|
+
|
45
|
+
def calculate_total_records(tables)
|
46
|
+
tables.sum { |table| table[:record_count] }
|
47
|
+
end
|
48
|
+
|
49
|
+
def find_largest_tables(tables, limit = 10)
|
50
|
+
tables.sort_by { |table| -table[:record_count] }.first(limit)
|
51
|
+
end
|
52
|
+
|
53
|
+
def find_empty_tables(tables)
|
54
|
+
tables.select { |table| table[:record_count] == 0 }
|
55
|
+
end
|
56
|
+
|
57
|
+
def calculate_average_records(tables)
|
58
|
+
return 0 if tables.empty?
|
59
|
+
|
60
|
+
(calculate_total_records(tables).to_f / tables.size).round(1)
|
61
|
+
end
|
37
62
|
end
|
38
63
|
end
|
39
64
|
end
|
@@ -7,7 +7,7 @@ module Dbviewer
|
|
7
7
|
before_action :set_global_filters, only: [ :show, :export_csv ]
|
8
8
|
|
9
9
|
def index
|
10
|
-
@tables =
|
10
|
+
@tables = fetch_tables(include_record_counts: true)
|
11
11
|
end
|
12
12
|
|
13
13
|
def show
|
@@ -60,7 +60,7 @@ module Dbviewer
|
|
60
60
|
def query
|
61
61
|
@read_only_mode = true # Flag to indicate we're in read-only mode
|
62
62
|
@columns = fetch_table_columns(@table_name)
|
63
|
-
@tables =
|
63
|
+
@tables = fetch_tables # Fetch tables for sidebar
|
64
64
|
|
65
65
|
prepare_query
|
66
66
|
execute_query
|
@@ -3,7 +3,7 @@
|
|
3
3
|
<div class="col">
|
4
4
|
<h1 class="h3 mb-2">Database Overview</h1>
|
5
5
|
<p class="database-connection-info">
|
6
|
-
Connected to database: <span class="badge rounded-pill database-name-badge"><%= get_database_name %></span>
|
6
|
+
Connected to <%= get_adapter_name %> database: <span class="badge rounded-pill database-name-badge"><%= get_database_name %></span>
|
7
7
|
</p>
|
8
8
|
</div>
|
9
9
|
</div>
|
@@ -180,8 +180,48 @@ module Dbviewer
|
|
180
180
|
@cache_manager.clear_all
|
181
181
|
end
|
182
182
|
|
183
|
+
# Calculate the total size of the database schema
|
184
|
+
# @return [Integer, nil] Database size in bytes or nil if unsupported
|
185
|
+
def fetch_schema_size
|
186
|
+
case adapter_name
|
187
|
+
when /mysql/
|
188
|
+
fetch_mysql_size
|
189
|
+
when /postgres/
|
190
|
+
fetch_postgres_size
|
191
|
+
when /sqlite/
|
192
|
+
fetch_sqlite_size
|
193
|
+
else
|
194
|
+
nil # Unsupported database type for size calculation
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
183
198
|
private
|
184
199
|
|
200
|
+
def fetch_mysql_size
|
201
|
+
query = "SELECT SUM(data_length + index_length) AS size FROM information_schema.TABLES WHERE table_schema = DATABASE()"
|
202
|
+
fetch_size_from_query(query)
|
203
|
+
end
|
204
|
+
|
205
|
+
def fetch_postgres_size
|
206
|
+
query = "SELECT pg_database_size(current_database()) AS size"
|
207
|
+
fetch_size_from_query(query)
|
208
|
+
end
|
209
|
+
|
210
|
+
def fetch_sqlite_size
|
211
|
+
page_count = fetch_sqlite_pragma_value("page_count")
|
212
|
+
page_size = fetch_sqlite_pragma_value("page_size")
|
213
|
+
page_count * page_size
|
214
|
+
end
|
215
|
+
|
216
|
+
def fetch_sqlite_pragma_value(pragma_name)
|
217
|
+
execute_sqlite_pragma(pragma_name).first.values.first.to_i
|
218
|
+
end
|
219
|
+
|
220
|
+
def fetch_size_from_query(query)
|
221
|
+
result = execute_query(query).first
|
222
|
+
result ? result["size"].to_i : nil
|
223
|
+
end
|
224
|
+
|
185
225
|
# Ensure we have a valid database connection
|
186
226
|
# @return [ActiveRecord::ConnectionAdapters::AbstractAdapter] The database connection
|
187
227
|
def ensure_connection
|
data/lib/dbviewer/engine.rb
CHANGED
@@ -2,9 +2,10 @@ module Dbviewer
|
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
isolate_namespace Dbviewer
|
4
4
|
|
5
|
-
#
|
6
|
-
|
7
|
-
config.
|
5
|
+
# Autoload lib directory
|
6
|
+
lib_path = File.expand_path("..", __dir__)
|
7
|
+
config.autoload_paths << lib_path
|
8
|
+
config.eager_load_paths << lib_path
|
8
9
|
|
9
10
|
# Register generators
|
10
11
|
config.app_generators do |g|
|
@@ -18,10 +19,27 @@ module Dbviewer
|
|
18
19
|
end
|
19
20
|
|
20
21
|
initializer "dbviewer.notifications" do
|
22
|
+
return unless Rails.env.development?
|
23
|
+
|
21
24
|
ActiveSupport::Notifications.subscribe("sql.active_record") do |*args|
|
22
25
|
event = ActiveSupport::Notifications::Event.new(*args)
|
23
|
-
|
26
|
+
|
27
|
+
next if skip_internal_query?(event)
|
28
|
+
|
29
|
+
Dbviewer::Logger.instance.add(event)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def skip_internal_query?(event)
|
36
|
+
caller_locations = caller_locations(1)
|
37
|
+
return false unless caller_locations
|
38
|
+
|
39
|
+
excluded_caller_locations = caller_locations.filter do |caller_location|
|
40
|
+
!caller_location.path.include?("lib/dbviewer/engine.rb")
|
24
41
|
end
|
42
|
+
excluded_caller_locations.any? { |l| l.path.include?("dbviewer") }
|
25
43
|
end
|
26
44
|
end
|
27
45
|
end
|
data/lib/dbviewer/logger.rb
CHANGED
@@ -21,7 +21,7 @@ module Dbviewer
|
|
21
21
|
timestamp: current_time,
|
22
22
|
duration_ms: event.duration.round(2),
|
23
23
|
binds: QueryParser.format_binds(event.payload[:binds]),
|
24
|
-
request_id:
|
24
|
+
request_id: ActiveSupport::Notifications.instrumenter.id,
|
25
25
|
thread_id: Thread.current.object_id.to_s,
|
26
26
|
caller: event.payload[:caller]
|
27
27
|
})
|
@@ -22,36 +22,6 @@ module Dbviewer
|
|
22
22
|
.gsub(/"[^"]*"/, '"X"')
|
23
23
|
end
|
24
24
|
|
25
|
-
# Check if the query is from the DBViewer library
|
26
|
-
def self.from_dbviewer?(event)
|
27
|
-
# Check if the SQL itself references DBViewer tables
|
28
|
-
if event.payload[:sql].match(/\b(from|join|update|into)\s+["`']?dbviewer_/i)
|
29
|
-
return true
|
30
|
-
end
|
31
|
-
|
32
|
-
# Check the caller information if available
|
33
|
-
caller = event.payload[:caller]
|
34
|
-
if caller.is_a?(String) && caller.include?("/dbviewer/")
|
35
|
-
return true
|
36
|
-
end
|
37
|
-
|
38
|
-
# Check if query name indicates it's from DBViewer
|
39
|
-
if event.payload[:name].is_a?(String) &&
|
40
|
-
(event.payload[:name].include?("Dbviewer") || event.payload[:name].include?("DBViewer") || event.payload[:name] == "SQL")
|
41
|
-
return true
|
42
|
-
end
|
43
|
-
|
44
|
-
# Check for common DBViewer operations
|
45
|
-
sql = event.payload[:sql].downcase
|
46
|
-
if sql.include?("table_structure") ||
|
47
|
-
sql.include?("schema_migrations") ||
|
48
|
-
sql.include?("database_analytics")
|
49
|
-
return true
|
50
|
-
end
|
51
|
-
|
52
|
-
false
|
53
|
-
end
|
54
|
-
|
55
25
|
# Format bind parameters for storage
|
56
26
|
def self.format_binds(binds)
|
57
27
|
return [] unless binds.respond_to?(:map)
|
@@ -70,13 +40,14 @@ module Dbviewer
|
|
70
40
|
end
|
71
41
|
|
72
42
|
# Determine if a query should be skipped based on content
|
43
|
+
# Rails and ActiveRecord often run internal queries that are not useful for logging
|
73
44
|
def self.should_skip_query?(event)
|
74
45
|
event.payload[:name] == "SCHEMA" ||
|
75
46
|
event.payload[:sql].include?("SHOW TABLES") ||
|
76
47
|
event.payload[:sql].include?("sqlite_master") ||
|
77
48
|
event.payload[:sql].include?("information_schema") ||
|
78
|
-
event.payload[:sql].include?("
|
79
|
-
|
49
|
+
event.payload[:sql].include?("schema_migrations") ||
|
50
|
+
event.payload[:sql].include?("pg_catalog")
|
80
51
|
end
|
81
52
|
end
|
82
53
|
end
|
data/lib/dbviewer/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dbviewer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wailan Tirajoh
|
@@ -100,7 +100,6 @@ files:
|
|
100
100
|
- lib/dbviewer/table_query_params.rb
|
101
101
|
- lib/dbviewer/version.rb
|
102
102
|
- lib/generators/dbviewer/initializer_generator.rb
|
103
|
-
- lib/generators/dbviewer/structured_api_generator.rb
|
104
103
|
- lib/generators/dbviewer/templates/initializer.rb
|
105
104
|
- lib/tasks/dbviewer_tasks.rake
|
106
105
|
homepage: https://github.com/wailantirajoh/dbviewer
|
@@ -1,11 +0,0 @@
|
|
1
|
-
module Dbviewer
|
2
|
-
module Generators
|
3
|
-
class StructuredApiGenerator < Rails::Generators::Base
|
4
|
-
source_root File.expand_path("../templates", __FILE__)
|
5
|
-
|
6
|
-
def create_initializer
|
7
|
-
template "structured_api_initializer.rb", "config/initializers/dbviewer_structured_api.rb"
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|