【问题标题】:Set database.yml using environment variables in Sinatra在 Sinatra 中使用环境变量设置 database.yml
【发布时间】:2015-08-22 15:54:43
【问题描述】:

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

我的文件存储在某个位置/etc/config/config.json,其中包含数据库信息,如HostPortUsernamePassword或大致如下所示:

{ 
      "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']}")

这不会设置环境变量MYSQL_DB_HOSTconfig/database.yml 文件使用的其他变量。

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

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

【问题讨论】:

    标签: mysql ruby orm sinatra sinatra-activerecord


    【解决方案1】:

    我感觉 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
    

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      我假设此配置文件超出了您的应用程序的范围,否则您可以直接读取 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)
      

      【讨论】:

      • 生成全新的“database.yaml”的想法对我有用。
      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2016-08-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-23
        • 2013-03-04
        • 2015-10-21
        • 2018-08-28
        相关资源
        最近更新 更多