在Sinatra中使用环境变量设置database.yml

时间:2015-06-08 08:51:32

标签: mysql ruby orm sinatra sinatra-activerecord

我正在处理的项目中有一个非常奇怪的要求。

我的文件存储在某个位置/etc/config/config.json,其中包含HostPortUsernamePassword等数据库信息,或大致如下所示:< / 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_HOSTconfig/database.yml文件要使用的其他变量。

知道如何完成这项工作吗?

我能想到的一种方法是“在阅读database.yml参数后动态生成整个config.json文件。 但是想知道是否有更好的解决方案。

3 个答案:

答案 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'] %>