我正在浏览"The Rails 7 Way",我阅读了以下段落:
Rails社区中的一种古老的最佳实践不是将
config/database.yml
存储在版本控制中。最重要的是,如果黑客获得对应用程序存储库的访问权限,则它们将在您的生产数据库中拥有所有连接设置。此外,团队的开发人员可能具有不同的开发和测试数据库设置。这使每个从事项目的开发人员都可以拥有自己的config/database.yml
副本,该副本不存储在版本控件中。
这绝对是正确的:过去15年中,我与之合作的大多数Rails开发人员都认为这是版本控制系统中 not 存储config/database.yml
的最佳实践。但是,这仍然是现代铁路应用程序的最佳实践吗?
让我们探索。
一些历史
首先,让我们看看在Rails的初始版本中,该文件的外观。这是从DHH's now famous 15 minute blog video from 2005拍摄的屏幕截图:
最初的database.yml
非常简单(很可能是故意的),基本上包含以下内容:
development:
adapter: mysql
database: blog_development
host: localhost
username: root
password:
test:
adapter: mysql
database: blog_test
host: localhost
username: root
password:
production:
adapter: mysql
database: blog_production
host: localhost
username: root
password:
但是,人们很快注意到有很多重复,因此使用yaml Merge键去除重复变得很常见,因此上述database.yml
将转换为:
defaults: &defaults
adapter: mysql
username: root
password:
host: localhost
development:
<<: *defaults
database: blog_development
test:
<<: *defaults
database: blog_test
production:
<<: *defaults
database: blog_production
这种方法变得很流行,并且被包括在"Rails Recipes" book by Chad Fowler中。我认为大卫试图在15分钟的视频(在3:09上)做类似的事情,但弄乱了YAML语法。
现在,显而易见的问题是您需要一个用户名和密码来连接到数据库进行开发,但并非所有开发人员都使用root
数据库帐户,而通过源控制共享生产数据库密码是一个重要的安全问题。
为了解决此问题,开发人员通常选择了以下方法之一:
- 在
config/database.yml.example
文件中检查并配置版本控制软件以忽略config/database.yml
- 在
config/database.yml
文件中检查,但使用erb从环境变量中填充username
或password
等值。
在这两种情况下,差异都很小,因为大多数团队都有某种自动化(如using the koude11 script)。但是,我看到了第一种方法的偏爱,因为:
- 开发人员不能意外地对
config/database.yml
承担凭据,因为它被忽略了 - Capistrano在部署后(koude13 variable documentation specifically mentions koude3)内置了对Symlink-ing-symlink-ing的支持,如果已经存在一个文件,它将失败
过去十年的变化
存储诸如密码之类的秘密的问题不仅限于数据库,因为越来越多的应用程序开始与诸如Amazon S3之类的第三方服务集成。
存储凭据需要几个迭代:
- rails 4.1 added support for koude15,作为与秘密互动的统一界面
- 基于在
sekrets
Gem上完成的工作,Rails 5.1引入了encrypted secrets,因此您可以使用所有必需的秘密检查加密的config/secrets.yml.enc
,并使用主密钥来解码 - Rails 5.2 switched to credentials和弃用
config/secrets.yml.enc
- Rails 6.0对encrypted credentials for multiple environments的添加支持
由于在读取database.yml
文件之前已加载凭据,因此我们可以重新访问defaults
块,因此它使用加密的凭据:
defaults: &defaults
adapter: mysql
username: root
password: <%= Rails.application.credentials.database_password %>
host: localhost
但是,由于Rails 4.1有support for the koude21 environment variable which allowed you to override the koude0 settings。
这对于像Heroku这样的平台很有用,因为现在它们可以提供整个连接路径的DATABASE_URL
环境变量,并在您的config/database.yml
中覆盖数据库名称(以前Heroku的方法是编写一个新文件,这可能会导致原因其他问题)。
改善默认值
Ruby在Rails上已经存在了近二十年,许多默认设置发生了很大变化,包括数据库设置,以使开发人员可以从开箱即用。
我认为,当涉及到初始设置时,我们可以在允许同事运行数据库的能力方面进行一些便利,但是他们认为合适,因为有些可能对无密码mysql root帐户不满意,有些人可能不满意不希望使用密码的额外麻烦。
mysql
如果您创建了一个新的Rails 7.0应用程序,则默认config/database.yml
看起来像这样,假设您选择了MySQL作为数据库:
# MySQL. Versions 5.5.8 and up are supported.
#
# Install the MySQL driver
# gem install mysql2
#
# Ensure the MySQL gem is defined in your Gemfile
# gem "mysql2"
#
# And be sure to use new-style password hashing:
# https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html
#
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password:
socket: /var/run/mysqld/mysqld.sock
development:
<<: *default
database: blog_development
# 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: blog_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="mysql2://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:
<<: *default
database: blog_production
username: blog
password: <%= ENV["BLOG_DATABASE_PASSWORD"] %>
这里有一些想法:
- 我们不需要初始申请设置后的第一条评论行,因为
mysql2
GEM将添加到Gemfile
- 我们可以将
username
,password
和socket
设置移至默认的~/.my.cnf
配置文件,从而使开发人员可以在看到fit fit 时将其设置为
- 在大多数情况下,我们将在生产环境中定义一个
DATABASE_URL
,覆盖数据库配置文件中我们拥有的任何设置,因此可以删除username
和password
部分寻找什么
这是稍微更好的config/database.yml
:
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
default_file: ~/.my.cnf
development:
<<: *default
database: blog_development
# 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: blog_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="mysql2://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:
<<: *default
database: blog_production
这是一个示例~/.my.cnf
文件:
[client]
user = andrei
password = AMERCE_sewage9borsch
socket = /var/run/mysqld/mysqld.sock
Postgresql
Rails生成的config/database.yml
用于PostgreSQL数据库如下所示:
# 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 macOS with MacPorts:
# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/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: blog_development
# The specified database role being used to connect to postgres.
# To create additional roles in postgres see `$ createuser --help`.
# When left blank, postgres will use the default role. This is
# the same name as the operating system user running Rails.
#username: blog
# The password associated with the postgres 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: blog_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:
<<: *default
database: blog_production
username: blog
password: <%= ENV["blog_DATABASE_PASSWORD"] %>
的评论比默认的mySQL版本要多一些,但这很可能是因为使用PostgreSQL和Rails开箱即用的设置可能不起作用。
您需要做的第一件事是创建一个与您的系统用户名匹配的超级用户帐户,因此您可以创建和破坏数据库(还有更多的粒度权限,但我们正在谈论开发机器,所以...) :
create user andrei superuser login password 'accursed5ground_BACILLI';
只需将andrei
替换为您的帐户名。
然后,创建一个存储密码的~/.pgpass
文件。这是一个例子:
localhost:*:*:andrei:accursed5ground_BACILLI
请记住,.pgpass
文件的行为与~/.my.cnf
文件的行为不相同,这意味着连接到localhost不会强迫username
和password
,而是在连接host,port,port,database时提供密码usename匹配一行。
然后,我们可以在config/database.yml
文件中应用相同的处理方法,但是我们不必指定default_file
,因为Postgres使用了系统帐户并自动访问.pgpass
文件:
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: blog_development
# 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: blog_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:
<<: *default
database: blog_production
就是这样!