Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable DATABASE_URL to control the placement of all of the databases #114

Merged
merged 1 commit into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lib/generators/dockerfile_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ def generate_app

template "docker-compose.yml.erb", "docker-compose.yml" if options.compose

template "database.yml.erb", "config/database.yml" if fix_database_config

if using_litefs?
template "litefs.yml.erb", "config/litefs.yml"

Expand Down Expand Up @@ -1450,4 +1452,31 @@ def fly_make_toml

toml
end

# if there are multiple production databases defined, allow them all to be
# configured via DATABASE_URL.
def fix_database_config
yaml = IO.read("config/database.yml")

production = YAML.load(yaml, aliases: true)["production"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually hard breaks the generate run because not all database.yml files are valid before the erb preprocessing causing this to error.

return unless production.is_a?(Hash) && production.values.all?(Hash)
return if production.keys == [ "primary" ]

section = yaml[/^(production:.*?)(^\S|\z)/m, 1]

replacement = section.gsub(/( ).*?\n((\1\s+).*?\n)*/) do |subsection|
spaces = $3
name = subsection[/\w+/]

if /^ +url:/.match?(subsection)
subsection
elsif name == "primary"
subsection + spaces + %(url: <%= ENV["DATABASE_URL"] %>\n)
else
subsection + spaces + %(url: <%= URI.parse(ENV["DATABASE_URL"]).tap { |url| url.path += "_#{name}" } if ENV["DATABASE_URL"] %>\n)
end
end

yaml.sub(section, replacement)
end
end
1 change: 1 addition & 0 deletions lib/generators/templates/database.yml.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= fix_database_config %>
10 changes: 10 additions & 0 deletions test/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ def check_entrypoint
assert_equal expected, results
end

def check_database_config
results = IO.read("config/database.yml")

IO.write("#{@results}/database.yml", results) if @capture

expected = IO.read("#{@results}/database.yml")

assert_equal expected, results
end

def teardown
return if ENV["TEST_KEEP"]
Dir.chdir ".."
Expand Down
4 changes: 2 additions & 2 deletions test/results/postgresql/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@ USER rails:rails
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]
EXPOSE 80
CMD ["bundle", "exec", "thrust", "./bin/rails", "server"]
102 changes: 102 additions & 0 deletions test/results/postgresql/database.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# PostgreSQL. Versions 9.3 and up are supported.
#
# Install the pg driver:
# gem install pg
# On macOS with Homebrew:
# gem install pg -- --with-pg-config=/usr/local/bin/pg_config
# On Windows:
# gem install pg
# Choose the win32 build.
# Install PostgreSQL and put its /bin directory on your path.
#
# Configure Using Gemfile
# gem "pg"
#
default: &default
adapter: postgresql
encoding: unicode
# For details on connection pooling, see Rails configuration guide
# https://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>


development:
<<: *default
database: test_postgresql_development

# The specified database role being used to connect to PostgreSQL.
# To create additional roles in PostgreSQL see `$ createuser --help`.
# When left blank, PostgreSQL will use the default role. This is
# the same name as the operating system user running Rails.
#username: test_postgresql

# The password associated with the PostgreSQL role (username).
#password:

# Connect on a TCP socket. Omitted by default since the client uses a
# domain socket that doesn't need configuration. Windows does not have
# domain sockets, so uncomment these lines.
#host: localhost

# The TCP port the server listens on. Defaults to 5432.
# If your server runs on a different port number, change accordingly.
#port: 5432

# Schema search path. The server defaults to $user,public
#schema_search_path: myapp,sharedapp,public

# Minimum log levels, in increasing order:
# debug5, debug4, debug3, debug2, debug1,
# log, notice, warning, error, fatal, and panic
# Defaults to warning.
#min_messages: notice

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: test_postgresql_test

# As with config/credentials.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password or a full connection URL as an environment
# variable when you boot the app. For example:
#
# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
#
# If the connection URL is provided in the special DATABASE_URL environment
# variable, Rails will automatically merge its configuration values on top of
# the values provided in this file. Alternatively, you can specify a connection
# URL environment variable explicitly:
#
# production:
# url: <%= ENV["MY_APP_DATABASE_URL"] %>
#
# Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full overview on how database connection configuration can be specified.
#
production:
primary: &primary_production
<<: *default
database: test_postgresql_production
username: test_postgresql
password: <%= ENV["TEST_POSTGRESQL_DATABASE_PASSWORD"] %>
url: <%= ENV["DATABASE_URL"] %>
cache:
<<: *primary_production
database: test_postgresql_production_cache
migrations_paths: db/cache_migrate
url: <%= URI.parse(ENV["DATABASE_URL"]).tap { |url| url.path += "_cache" } if ENV["DATABASE_URL"] %>
queue:
<<: *primary_production
database: test_postgresql_production_queue
migrations_paths: db/queue_migrate
url: <%= URI.parse(ENV["DATABASE_URL"]).tap { |url| url.path += "_queue" } if ENV["DATABASE_URL"] %>
cable:
<<: *primary_production
database: test_postgresql_production_cable
migrations_paths: db/cable_migrate
url: <%= URI.parse(ENV["DATABASE_URL"]).tap { |url| url.path += "_cable" } if ENV["DATABASE_URL"] %>
3 changes: 2 additions & 1 deletion test/test_postgres.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
require_relative "base"

class TestPostgresql < TestBase
@rails_options = "--database=postgresql"
@rails_options = "--database=postgresql --main"
@generate_options = "--compose"

def test_postgresql
check_dockerfile
check_compose
check_database_config
end
end
Loading