Module: PgReports::Standalone

Extended by:
Standalone
Included in:
Standalone
Defined in:
lib/pg_reports/standalone.rb

Overview

Runs the dashboard as a self-contained application, without a host Rails app.

It boots a minimal Rails::Application that mounts PgReports::Engine and points ActiveRecord::Base at a PostgreSQL database, then serves it over HTTP. This is what powers the pg_reports server executable and the pg_reports:server rake task, so the project can be launched straight from the gem's root folder.

Dependency note: this relies only on gems already pulled in transitively by the gem's runtime deps (rack via actionpack, rackup via railties). The actual web server (puma / webrick) is resolved at run time and is NOT a hard dependency — installed-gem users bring their own.

Defined Under Namespace

Classes: ServerUnavailable

Constant Summary collapse

DEFAULT_PORT =
4000
DEFAULT_HOST =
"127.0.0.1"
DEFAULT_MOUNT =
"/"
CANDIDATE_SERVERS =

Rack handlers tried, in order, when none is named explicitly.

%w[puma webrick].freeze
DEFAULT_CONFIG_FILES =

Config files auto-loaded (first that exists), relative to the working directory, when no explicit --config path is given.

%w[pg_reports.rb config/pg_reports.rb].freeze

Instance Method Summary collapse

Instance Method Details

#connection_url(explicit = nil) ⇒ Object

Resolve the connection URL. Priority: explicit url > DATABASE_URL > libpq-style PG* env vars (PGHOST/PGPORT/PGUSER/PGPASSWORD/PGDATABASE).



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/pg_reports/standalone.rb', line 73

def connection_url(explicit = nil)
  return explicit if explicit && !explicit.empty?
  return ENV["DATABASE_URL"] if ENV["DATABASE_URL"] && !ENV["DATABASE_URL"].empty?

  require "erb"
  user = ENV["PGUSER"] || ENV["USER"]
  password = ENV["PGPASSWORD"]
  host = ENV["PGHOST"] || "localhost"
  port = ENV["PGPORT"] || 5432
  database = ENV["PGDATABASE"] || "postgres"

  userinfo = +""
  if user && !user.empty?
    userinfo << ERB::Util.url_encode(user)
    userinfo << ":#{ERB::Util.url_encode(password)}" if password && !password.empty?
    userinfo << "@"
  end

  "postgresql://#{userinfo}#{host}:#{port}/#{ERB::Util.url_encode(database)}"
end

#run(port: DEFAULT_PORT, host: DEFAULT_HOST, mount_path: DEFAULT_MOUNT, database_url: nil, server: nil, config_file: nil, overrides: {}) ⇒ Object

Boot the app and start a (blocking) web server.

Parameters:

  • port (Integer) (defaults to: DEFAULT_PORT)
  • host (String) (defaults to: DEFAULT_HOST)
  • mount_path (String) (defaults to: DEFAULT_MOUNT)

    where the engine is mounted (default "/")

  • database_url (String, nil) (defaults to: nil)

    explicit connection URL; otherwise resolved from DATABASE_URL or libpq-style PG* env vars

  • server (String, nil) (defaults to: nil)

    Rack handler name to force (e.g. "puma")

  • config_file (String, nil) (defaults to: nil)

    path to a Ruby config file that calls PgReports.configure; auto-detected from DEFAULT_CONFIG_FILES otherwise

  • overrides (Hash) (defaults to: {})

    per-setting overrides applied last (from CLI flags); nil values are ignored. Keys are Configuration attribute names.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/pg_reports/standalone.rb', line 45

def run(port: DEFAULT_PORT, host: DEFAULT_HOST, mount_path: DEFAULT_MOUNT,
  database_url: nil, server: nil, config_file: nil, overrides: {})
  # Rails' ActiveRecord railtie reads the connection from DATABASE_URL when no
  # config/database.yml exists — so we route our resolved connection through
  # it. The connection registry then auto-registers it as the :primary target,
  # and database switching / multi-cluster all work unchanged.
  ENV["DATABASE_URL"] = connection_url(database_url)

  # Mark this process as standalone so the dashboard can hide reports that
  # only make sense with a host app (e.g. Schema Analysis, which introspects
  # the host application's ActiveRecord models — there are none here).
  PgReports.config.standalone = true

  # Layer settings on top of the ENV-derived defaults: config file first, then
  # explicit CLI overrides win.
  apply_configuration(config_file: config_file, overrides: overrides)

  app = build_application(mount_path)
  app.initialize!
  verify_connection!

  handler_name, handler = resolve_server(server)
  banner(host: host, port: port, server: handler_name)
  handler.run(app, Host: host, Port: port)
end