我正在处理的项目中有一个非常奇怪的要求。
我的文件存储在某个位置/etc/config/config.json
,其中包含Host
,Port
,Username
或Password
等数据库信息,或大致如下所示:< / p>
{
"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
文件要使用的其他变量。
知道如何完成这项工作吗?
我能想到的一种方法是“在阅读database.yml
参数后动态生成整个config.json
文件。
但是想知道是否有更好的解决方案。
答案 0 :(得分:1)
我感觉Sinatra没有将环境变量处理到database.yml
文件中。 Rails确实......你可以做到这一点,但我认为这有点过分了。我认为您必须将YML文件作为ERB模板或其他内容。
其他一些选择:
动态编写database.yml
中的整个setup.rb
文件 - 虽然我不会这样做。它正常形成的负荷。
或者,使用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
希望这有帮助。
答案 1 :(得分:0)
我认为此配置文件超出了应用程序的范围,否则您可以直接读取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
我假设您可以将其他参数添加到哈希以获得类似波纹管配置的内容。
<强>配置/ production.yaml 强>
database:
adapter: mysql2
host: localhost
port: 3306
database: myappdb
username: myprodusername
password: myprodpassword
<强>配置/ 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)
答案 2 :(得分:0)
system
method创建一个新的子shell并在其中执行命令。当命令设置环境变量,然后在该子shell 中设置该环境变量时,更改不会传播回父进程。这意味着没有设置这些环境变量。
要在当前流程中设置环境变量,您只需直接访问ENV
即可。因此,而不是system("export MYSQL_DB_HOST=#{data['mysql-db']['host']}")
执行此操作:
ENV['MYSQL_DB_HOST'] = data['mysql-db']['host']
(和其他设置类似)。
这应该可以解决您的问题,但由于您是直接从json配置文件中自己阅读设置,因此可以说使用环境变量并不多。直接从Erb / Yaml文件访问设置会更直接。理想情况下,您希望以某种方式将设置传递给Erb评估,但是以任何方式对Erb评估的Sinatra-ActiveRecord doesn’t appear to allow you to set the binding or context。另一种方法是使用全局变量作为数据哈希:
# 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'] %>