在 Sinatra 中使用环境变量设置 database.yml
Set database.yml using environment variables in Sinatra
我在从事的项目中有一个非常奇怪的要求。
我将文件存储在某个位置 /etc/config/config.json
,其中包含 Host
、Port
、Username
或 Password
等数据库信息,或者大致如下所示:
{
"mysql-db": {
"host": "172.17.0.27",
"port": 3306,
"password": "root",
"username": "root"
}
}
我正在基于 Sinatra
构建我的小型网络应用程序,并使用 sinatra-activerecord 来处理 MySql
数据库。
我的 database.yml
文件如下所示:
development:
adapter: mysql2
database: toopaste
host: <%= ENV["MYSQL_DB_HOST"] %>
port: <%= ENV["MYSQL_DB_PORT"] %>
username: <%= ENV["MYSQL_DB_USERNAME"] %>
password: <%= ENV["MYSQL_DB_PASSWORD"] %>
我在尝试什么?
我创建了一个类似 setup.rb
的可执行文件:
#! /usr/bin/env ruby
require 'json'
FILE_PATH = "/etc/atlantis/config/konfig.json"
data = JSON.parse(File.read(FILE_PATH))
system("export MYSQL_DB_HOST=#{data['mysql-db']['host']}")
system("export MYSQL_DB_PORT=#{data['mysql-db']['port']}")
system("export MYSQL_DB_USERNAME=#{data['mysql-db']['username']}")
system("export MYSQL_DB_PASSWORD=#{data['mysql-db']['password']}")
这不会设置 env 变量 MYSQL_DB_HOST
或 config/database.yml
文件使用的其他变量。
知道如何完成这样的工作吗?
我能想到的一种方法是“在读取 config.json
参数后动态生成整个 database.yml
文件。
但想知道是否有更好的解决方案。
我感觉 Sinatra 没有将环境变量处理到 database.yml
文件中。 Rails 确实...您可以这样做,但我认为这有点麻烦。我认为你必须将 YML 文件作为 ERB 模板或其他东西通过。
一些其他选项:
从您的 setup.rb
动态写入整个 database.yml
文件 - 虽然我不会这样做。负载正常形成。
或者,使用 Sinatra 配置从您的首选文件中设置数据库连接详细信息。 sinatra-activerecord 中的示例请阅读我。
set :database, {adapter: 'mysql', database: ENV['MY_SQL_DB_HOST']}
这对我来说似乎更干净。事实上,我会走得更远,使用 Sinatra 配置来完成整个事情(加载文件,并从那里获取参数)。这样代码变得更明确,并且将来更容易更改。也就是说,这只是我的头脑,所以你可能需要调整:
configure do
FILE_PATH = "/etc/atlantis/config/konfig.json"
data = JSON.parse(File.read(FILE_PATH))
set :DB_PASSWORD = data['mysql-db']['password']
# ETC...
set :database, { ... }
end
希望对您有所帮助。
我假设这个配置文件超出了您的应用程序的范围,否则您可以直接读取 json 文件。否则,您可以使用 JSON 的解析器并将其转换为 YAML。像这样的东西会起作用:
require 'json'
require 'yaml'
json = JSON.parse(File.read('./test.json'))
database = Hash.new
database[:development] = json
File.open("./test.yaml","w"){|h| h.write database.to_yaml }
您的 YAML 应如下所示。
$ cat test.yaml
---
:development:
mysql-db:
host: 172.17.0.27
port: 3306
password: root
username: root
我假设您可以将额外的参数添加到散列中以获得类似下面的配置。
config/production.yaml
database:
adapter: mysql2
host: localhost
port: 3306
database: myappdb
username: myprodusername
password: myprodpassword
config/development.yaml
database:
adapter: mysql2
host: localhost
port: 3306
database: myappdb_dev
username: mydevuser
password: mydevpassword
然后像这样将它们加载到您的应用程序中。
config.ru
require 'sinatra'
require 'yaml'
configure :production do
@config = YAML.load_file("config/#{ENV["RACK_ENV"]}.yaml")
#some other things that you do in prod
end
configure :development do
@config = YAML.load_file("config/#{ENV["RACK_ENV"]}.yaml")
#some other things that you only do in dev
end
正在启动应用程序
$ RACK_ENV=development puma (or whatever other server you use like thin)
or for prod
$ RACK_ENV=production puma (or whatever other server you use like thin)
system
method创建一个新的子shell并在其中执行命令。当命令设置环境变量时,该环境变量在该子外壳 中设置 ,更改不会传播回父进程。这意味着没有设置这些环境变量。
要在当前进程中设置环境变量,直接访问ENV
即可。所以不要 system("export MYSQL_DB_HOST=#{data['mysql-db']['host']}")
这样做:
ENV['MYSQL_DB_HOST'] = data['mysql-db']['host']
(其他设置也类似)。
这应该可以解决您的问题,但是由于您是直接从 json 配置文件中自己读取设置,因此可以说使用环境变量没有多大意义。直接从 Erb/Yaml 文件访问设置会更直接。理想情况下,您希望以某种方式将设置传递给 Erb 评估,但 Sinatra-ActiveRecord doesn’t appear to allow you to set the binding or context 以任何方式传递给 Erb 评估。另一种方法是对数据哈希使用全局变量:
# When reading the json, use a global instead,
# and pick out the 'mysql-db' key
$data = JSON.parse(File.read(FILE_PATH))['mysql-db']
在database.yml
中:
development:
adapter: mysql2
database: toopaste
host: <%= $data['host'] %>
port: <%= $data['port'] %>
username: <%= $data['username'] %>
password: <%= $data['password'] %>
我在从事的项目中有一个非常奇怪的要求。
我将文件存储在某个位置 /etc/config/config.json
,其中包含 Host
、Port
、Username
或 Password
等数据库信息,或者大致如下所示:
{
"mysql-db": {
"host": "172.17.0.27",
"port": 3306,
"password": "root",
"username": "root"
}
}
我正在基于 Sinatra
构建我的小型网络应用程序,并使用 sinatra-activerecord 来处理 MySql
数据库。
我的 database.yml
文件如下所示:
development:
adapter: mysql2
database: toopaste
host: <%= ENV["MYSQL_DB_HOST"] %>
port: <%= ENV["MYSQL_DB_PORT"] %>
username: <%= ENV["MYSQL_DB_USERNAME"] %>
password: <%= ENV["MYSQL_DB_PASSWORD"] %>
我在尝试什么?
我创建了一个类似 setup.rb
的可执行文件:
#! /usr/bin/env ruby
require 'json'
FILE_PATH = "/etc/atlantis/config/konfig.json"
data = JSON.parse(File.read(FILE_PATH))
system("export MYSQL_DB_HOST=#{data['mysql-db']['host']}")
system("export MYSQL_DB_PORT=#{data['mysql-db']['port']}")
system("export MYSQL_DB_USERNAME=#{data['mysql-db']['username']}")
system("export MYSQL_DB_PASSWORD=#{data['mysql-db']['password']}")
这不会设置 env 变量 MYSQL_DB_HOST
或 config/database.yml
文件使用的其他变量。
知道如何完成这样的工作吗?
我能想到的一种方法是“在读取 config.json
参数后动态生成整个 database.yml
文件。
但想知道是否有更好的解决方案。
我感觉 Sinatra 没有将环境变量处理到 database.yml
文件中。 Rails 确实...您可以这样做,但我认为这有点麻烦。我认为你必须将 YML 文件作为 ERB 模板或其他东西通过。
一些其他选项:
从您的 setup.rb
动态写入整个 database.yml
文件 - 虽然我不会这样做。负载正常形成。
或者,使用 Sinatra 配置从您的首选文件中设置数据库连接详细信息。 sinatra-activerecord 中的示例请阅读我。
set :database, {adapter: 'mysql', database: ENV['MY_SQL_DB_HOST']}
这对我来说似乎更干净。事实上,我会走得更远,使用 Sinatra 配置来完成整个事情(加载文件,并从那里获取参数)。这样代码变得更明确,并且将来更容易更改。也就是说,这只是我的头脑,所以你可能需要调整:
configure do
FILE_PATH = "/etc/atlantis/config/konfig.json"
data = JSON.parse(File.read(FILE_PATH))
set :DB_PASSWORD = data['mysql-db']['password']
# ETC...
set :database, { ... }
end
希望对您有所帮助。
我假设这个配置文件超出了您的应用程序的范围,否则您可以直接读取 json 文件。否则,您可以使用 JSON 的解析器并将其转换为 YAML。像这样的东西会起作用:
require 'json'
require 'yaml'
json = JSON.parse(File.read('./test.json'))
database = Hash.new
database[:development] = json
File.open("./test.yaml","w"){|h| h.write database.to_yaml }
您的 YAML 应如下所示。
$ cat test.yaml
---
:development:
mysql-db:
host: 172.17.0.27
port: 3306
password: root
username: root
我假设您可以将额外的参数添加到散列中以获得类似下面的配置。
config/production.yaml
database:
adapter: mysql2
host: localhost
port: 3306
database: myappdb
username: myprodusername
password: myprodpassword
config/development.yaml
database:
adapter: mysql2
host: localhost
port: 3306
database: myappdb_dev
username: mydevuser
password: mydevpassword
然后像这样将它们加载到您的应用程序中。
config.ru
require 'sinatra'
require 'yaml'
configure :production do
@config = YAML.load_file("config/#{ENV["RACK_ENV"]}.yaml")
#some other things that you do in prod
end
configure :development do
@config = YAML.load_file("config/#{ENV["RACK_ENV"]}.yaml")
#some other things that you only do in dev
end
正在启动应用程序
$ RACK_ENV=development puma (or whatever other server you use like thin)
or for prod
$ RACK_ENV=production puma (or whatever other server you use like thin)
system
method创建一个新的子shell并在其中执行命令。当命令设置环境变量时,该环境变量在该子外壳 中设置 ,更改不会传播回父进程。这意味着没有设置这些环境变量。
要在当前进程中设置环境变量,直接访问ENV
即可。所以不要 system("export MYSQL_DB_HOST=#{data['mysql-db']['host']}")
这样做:
ENV['MYSQL_DB_HOST'] = data['mysql-db']['host']
(其他设置也类似)。
这应该可以解决您的问题,但是由于您是直接从 json 配置文件中自己读取设置,因此可以说使用环境变量没有多大意义。直接从 Erb/Yaml 文件访问设置会更直接。理想情况下,您希望以某种方式将设置传递给 Erb 评估,但 Sinatra-ActiveRecord doesn’t appear to allow you to set the binding or context 以任何方式传递给 Erb 评估。另一种方法是对数据哈希使用全局变量:
# When reading the json, use a global instead,
# and pick out the 'mysql-db' key
$data = JSON.parse(File.read(FILE_PATH))['mysql-db']
在database.yml
中:
development:
adapter: mysql2
database: toopaste
host: <%= $data['host'] %>
port: <%= $data['port'] %>
username: <%= $data['username'] %>
password: <%= $data['password'] %>