Skip to content

Commit

Permalink
Merge pull request rails#13463 from josevalim/jv-env
Browse files Browse the repository at this point in the history
Do not store production information in .yml files
  • Loading branch information
José Valim committed Dec 23, 2013
2 parents 7530c82 + 2d4cfb2 commit 33cb2f3
Show file tree
Hide file tree
Showing 20 changed files with 113 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,43 @@ def initialize_dup(original)
##
# Builds a ConnectionSpecification from user input
class Resolver # :nodoc:
attr_reader :config, :klass, :configurations
attr_reader :configurations

def initialize(config, configurations)
@config = config
def initialize(configurations)
@configurations = configurations
end

def spec
case config
when nil
raise AdapterNotSpecified unless defined?(Rails.env)
resolve_string_connection Rails.env
when Symbol, String
resolve_string_connection config.to_s
when Hash
resolve_hash_connection config
def resolve(config)
if config
resolve_connection config
elsif defined?(Rails.env)
resolve_env_connection Rails.env
else
raise AdapterNotSpecified
end
end

private
def resolve_string_connection(spec) # :nodoc:
hash = configurations.fetch(spec) do |k|
connection_url_to_hash(k)
end

raise(AdapterNotSpecified, "#{spec} database is not configured") unless hash
def resolve_connection(spec) #:nodoc:
case spec
when Symbol, String
resolve_env_connection spec.to_s
when Hash
resolve_hash_connection spec
end
end

resolve_hash_connection hash
def resolve_env_connection(spec) # :nodoc:
# Rails has historically accepted a string to mean either
# an environment key or a url spec. So we support both for
# now but it would be nice to limit the environment key only
# for symbols.
spec = configurations.fetch(spec.to_s) do
resolve_string_connection(spec) if spec.is_a?(String)
end
raise(AdapterNotSpecified, "#{spec} database is not configured") unless spec
resolve_connection spec
end

def resolve_hash_connection(spec) # :nodoc:
Expand All @@ -65,8 +74,8 @@ def resolve_hash_connection(spec) # :nodoc:
ConnectionSpecification.new(spec, adapter_method)
end

def connection_url_to_hash(url) # :nodoc:
config = URI.parse url
def resolve_string_connection(spec) # :nodoc:
config = URI.parse spec
adapter = config.scheme
adapter = "postgresql" if adapter == "postgres"

Expand Down
4 changes: 2 additions & 2 deletions activerecord/lib/active_record/connection_handling.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ module ConnectionHandling
# The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
# may be returned on an error.
def establish_connection(spec = ENV["DATABASE_URL"])
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new spec, configurations
spec = resolver.spec
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new configurations
spec = resolver.resolve(spec)

unless respond_to?(spec.adapter_method)
raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
Expand Down
15 changes: 14 additions & 1 deletion activerecord/lib/active_record/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,24 @@ class Railtie < Rails::Railtie # :nodoc:
namespace :db do
task :load_config do
ActiveRecord::Tasks::DatabaseTasks.db_dir = Rails.application.config.paths["db"].first
ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration
ActiveRecord::Tasks::DatabaseTasks.migrations_paths = Rails.application.paths['db/migrate'].to_a
ActiveRecord::Tasks::DatabaseTasks.fixtures_path = File.join Rails.root, 'test', 'fixtures'
ActiveRecord::Tasks::DatabaseTasks.root = Rails.root

configuration = if ENV["DATABASE_URL"]
{ Rails.env => ENV["DATABASE_URL"] }
else
Rails.application.config.database_configuration || {}
end

resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(configuration)

configuration.each do |key, value|
configuration[key] = resolver.resolve(value) if value
end

ActiveRecord::Tasks::DatabaseTasks.database_configuration = configuration

if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
if engine.paths['db/migrate'].existent
ActiveRecord::Tasks::DatabaseTasks.migrations_paths += engine.paths['db/migrate'].to_a
Expand Down
12 changes: 2 additions & 10 deletions activerecord/lib/active_record/railties/databases.rake
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ db_namespace = namespace :db do

desc 'Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all databases in the config)'
task :create => [:load_config] do
if ENV['DATABASE_URL']
ActiveRecord::Tasks::DatabaseTasks.create_database_url
else
ActiveRecord::Tasks::DatabaseTasks.create_current
end
ActiveRecord::Tasks::DatabaseTasks.create_current
end

namespace :drop do
Expand All @@ -29,11 +25,7 @@ db_namespace = namespace :db do

desc 'Drops the database using DATABASE_URL or the current Rails.env (use db:drop:all to drop all databases)'
task :drop => [:load_config] do
if ENV['DATABASE_URL']
ActiveRecord::Tasks::DatabaseTasks.drop_database_url
else
ActiveRecord::Tasks::DatabaseTasks.drop_current
end
ActiveRecord::Tasks::DatabaseTasks.drop_current
end

desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
Expand Down
19 changes: 1 addition & 18 deletions activerecord/lib/active_record/tasks/database_tasks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,7 @@ def current_config(options = {})
if options.has_key?(:config)
@current_config = options[:config]
else
@current_config ||= if ENV['DATABASE_URL']
database_url_config
else
ActiveRecord::Base.configurations[options[:env]]
end
@current_config ||= ActiveRecord::Base.configurations[options[:env]]
end
end

Expand All @@ -85,10 +81,6 @@ def create_current(environment = env)
ActiveRecord::Base.establish_connection environment
end

def create_database_url
create database_url_config
end

def drop(*arguments)
configuration = arguments.first
class_for_adapter(configuration['adapter']).new(*arguments).drop
Expand All @@ -107,10 +99,6 @@ def drop_current(environment = env)
}
end

def drop_database_url
drop database_url_config
end

def charset_current(environment = env)
charset ActiveRecord::Base.configurations[environment]
end
Expand Down Expand Up @@ -165,11 +153,6 @@ def load_seed

private

def database_url_config
@database_url_config ||=
ConnectionAdapters::ConnectionSpecification::Resolver.new(ENV["DATABASE_URL"], {}).spec.config.stringify_keys
end

def class_for_adapter(adapter)
key = @tasks.keys.detect { |pattern| adapter[pattern] }
unless key
Expand Down
12 changes: 10 additions & 2 deletions activerecord/test/cases/connection_specification/resolver_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ module ActiveRecord
module ConnectionAdapters
class ConnectionSpecification
class ResolverTest < ActiveRecord::TestCase
def resolve(spec)
Resolver.new(spec, {}).spec.config
def resolve(spec, config={})
Resolver.new(config).resolve(spec).config
end

def test_url_invalid_adapter
Expand All @@ -17,6 +17,14 @@ def test_url_invalid_adapter
# The abstract adapter is used simply to bypass the bit of code that
# checks that the adapter file can be required in.

def test_url_from_environment
spec = resolve :production, 'production' => 'abstract://foo?encoding=utf8'
assert_equal({
adapter: "abstract",
host: "foo",
encoding: "utf8" }, spec)
end

def test_url_host_no_db
spec = resolve 'abstract://foo?encoding=utf8'
assert_equal({
Expand Down
5 changes: 5 additions & 0 deletions railties/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
* Configure `secrets.yml` and `database.yml` to read configuration
from the system environment by default for production.

*José Valim*

* `config.assets.raise_runtime_errors` is set to true by default

This option has been introduced in
Expand Down
5 changes: 2 additions & 3 deletions railties/lib/rails/commands/dbconsole.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,8 @@ def config
@config ||= begin
require APP_PATH
ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(
ENV['DATABASE_URL'],
(Rails.application.config.database_configuration || {})
).spec.config.stringify_keys
Rails.application.config.database_configuration || {}
).resolve(ENV["DATABASE_URL"]).config.stringify_keys
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ test:
<<: *default
database: <%= app_name %>_test

production:
<<: *default
database: <%= app_name %>_production
# Do not keep production credentials in the repository,
# instead read the configuration from the environment.
production: <%%= ENV["RAILS_DATABASE_URL"] %>
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,6 @@ test:
<<: *default
database: <%= app_name[0,4] %>_tst

production:
<<: *default
database: <%= app_name[0,8] %>
# Do not keep production credentials in the repository,
# instead read the configuration from the environment.
production: <%%= ENV["RAILS_DATABASE_URL"] %>
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@ test:
<<: *default
url: jdbc:db://localhost/<%= app_name %>_test

production:
<<: *default
url: jdbc:db://localhost/<%= app_name %>_production
# Do not keep production credentials in the repository,
# instead read the configuration from the environment.
production: <%%= ENV["RAILS_DATABASE_URL"] %>
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ test:
<<: *default
database: <%= app_name %>_test

production:
<<: *default
database: <%= app_name %>_production
# Do not keep production credentials in the repository,
# instead read the configuration from the environment.
production: <%%= ENV["RAILS_DATABASE_URL"] %>
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ test:
<<: *default
database: <%= app_name %>_test

production:
<<: *default
database: <%= app_name %>_production
# Do not keep production credentials in the repository,
# instead read the configuration from the environment.
production: <%%= ENV["RAILS_DATABASE_URL"] %>
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ test:
<<: *default
database: db/test.sqlite3

production:
<<: *default
database: db/production.sqlite3
# Do not keep production credentials in the repository,
# instead read the configuration from the environment.
production: <%%= ENV["RAILS_DATABASE_URL"] %>
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ test:
<<: *default
database: <%= app_name %>_test

production:
<<: *default
database: <%= app_name %>_production
# Avoid production credentials in the repository,
# instead read the configuration from the environment.
#
# Example:
# mysql2://myuser:mypass@localhost/somedatabase
#
production: <%%= ENV["RAILS_DATABASE_URL"] %>
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ test:
<<: *default
database: <%= app_name %>_test

production:
<<: *default
database: <%= app_name %>_production
# Do not keep production credentials in the repository,
# instead read the configuration from the environment.
production: <%%= ENV["RAILS_DATABASE_URL"] %>
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ test:
<<: *default
database: <%= app_name %>_test

production:
<<: *default
database: <%= app_name %>_production
# Do not keep production credentials in the repository,
# instead read the configuration from the environment.
#
# Example:
# postgres://myuser:mypass@localhost/somedatabase
#
production: <%%= ENV["RAILS_DATABASE_URL"] %>
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ test:
<<: *default
database: db/test.sqlite3

production:
<<: *default
database: db/production.sqlite3
# Do not keep production credentials in the repository,
# instead read the configuration from the environment.
#
# Example:
# sqlite3://myuser:mypass@localhost/somedatabase
#
production: <%%= ENV["RAILS_DATABASE_URL"] %>
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ test:
<<: *default
database: <%= app_name %>_test

production:
<<: *default
database: <%= app_name %>_production
# Do not keep production credentials in the repository,
# instead read the configuration from the environment.
production: <%%= ENV["RAILS_DATABASE_URL"] %>
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ development:
test:
secret_key_base: <%= app_secret %>

# This YAML file is processed by ERB first (as others). In particular the
# production environment can set the secret via an environment variable
# this way:
#
# secret_key_base: <%%= ENV['SECRET_KEY_BASE'] %>
#
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= app_secret %>
secret_key_base: <%%= ENV["RAILS_SECRET_KEY_BASE"] %>

0 comments on commit 33cb2f3

Please sign in to comment.