class HerokuExternalDb::Configuration

Represents an ActiveRecord database configuration to be used in a Heroku app. This configuration consists of at least one environment variable, and possibly several:

Attributes

ca_path[W]
configuration_name[R]

The ActiveRecord configuration that will be set up. Typically this should be the same as your RAILS_ENV environment variable, but some apps may have multiple database connections with different names.

env_prefix[R]

Each HerokuExternalDb must have a unique prefix for its environment variables. For example, if the prefix was set to CRAZY, then the database URL would be taken from CRAZY_DATABASE_URL, and the CA filename would be taken from CRAZY_DATABASE_CA, if it existed.

In typical usage, the prefix will be EXTERNAL by default.

Public Class Methods

new(env_prefix, configuration_name) click to toggle source
# File lib/heroku_external_db.rb, line 43
def initialize(env_prefix, configuration_name)
  @env_prefix = env_prefix
  @configuration_name = configuration_name
end

Public Instance Methods

ca_path() click to toggle source

The path in which your SSL CA certificates are stored. By default, this is +[Rails app root]/config/ca+.

# File lib/heroku_external_db.rb, line 50
def ca_path
  @ca_path ||= ca_path_from_rails_root
end
db_config() click to toggle source

Returns an ActiveRecord configuration hash based on the environment variables.

# File lib/heroku_external_db.rb, line 103
def db_config
  @db_config ||= begin 
    raise "ENV['#{env_prefix}_DATABASE_URL'] expected but not found!" unless ENV["#{env_prefix}_DATABASE_URL"]
    config = parse_db_uri(ENV["#{env_prefix}_DATABASE_URL"])

    if ENV["#{env_prefix}_DATABASE_CA"]
      config.merge!(db_configuration({
        :sslca => ENV["#{env_prefix}_DATABASE_CA"],
        :sslcert => ENV["#{env_prefix}_DATABASE_CERT"],
        :sslkey => ENV["#{env_prefix}_DATABASE_KEY"],
      }))
    end
  
    config
  end
end
db_configuration(opts) click to toggle source

Returns a partial ActiveRecord configuration hash for the given SSL CA certificate. Checks to make sure the given filename actually exists, and raises an error if it does not.

# File lib/heroku_external_db.rb, line 79
def db_configuration(opts)
  return {} unless opts
  raise "ca_path for #{opts.inspect} cannot be determined from Rails root; please set it explicitly" unless ca_path

  config = {}

  [
    :sslca,

    # Needed when using X.509
    :sslcert,
    :sslkey,
  ].each do |k|
    if value = opts[k]
      filepath = File.join(ca_path, value)
      raise "File #{filepath.inspect} does not exist!" unless File.exists?(filepath)
      config[k] = filepath
    end
  end

  return config
end
parse_db_uri(db_uri) click to toggle source

Parse a Heroku-style database URI and return an ActiveRecord configuration hash based on it. Format is as follows:

<adapter>://[<username>[:<password>]]@<host>[:<port>]/<database>
# File lib/heroku_external_db.rb, line 58
def parse_db_uri(db_uri)
  uri = URI.parse(db_uri)

  db_config = {
    :adapter => uri.scheme,
    :database => uri.path[1..-1],
    :host => uri.host
  }

  if uri.user
    db_config[:username] = uri.user
    db_config[:password] = uri.password if uri.password
  end
  db_config[:port] = uri.port if uri.port

  db_config
end
setup!() click to toggle source

Installs an ActiveRecord configuration based on the environment variables, and makes an initial connection to the database. (This flushes out the connection pool if a different connection has already been established, and tests to make sure we can actually connect.)

# File lib/heroku_external_db.rb, line 124
def setup!
  ActiveRecord::Base.configurations[configuration_name] = db_config
  ActiveRecord::Base.establish_connection(configuration_name).connection
  self
end

Protected Instance Methods

ca_path_from_rails_root() click to toggle source
# File lib/heroku_external_db.rb, line 131
def ca_path_from_rails_root
  if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
    File.join(Rails.root, 'config', 'ca')
  end
end