是否可以在我的代码中为Rails开发环境设置ENV变量?


82

我知道我可以通过以下方式在bash中设置我的ENV变量

export admin_password = "secret"

但是有办法在我的rails源代码中的某个地方吗?我的第一次尝试是这样的environment/development.rb

ENV['admin_password'] = "secret"

但这没有用。有没有办法做到这一点?


请注意,bash命令应为export admin_password="secret"而不是export admin_password = "secret"
雅各布·洛克德

Answers:


81

[更新]

虽然“旧答案”下的解决方案适用于一般性问题,但本节将在您的评论澄清后回答您的特定问题。

您应该能够完全按照您在问题中指定的方式设置环境变量。例如,我有一个使用HTTP基本身份验证的Heroku应用程序。

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery
  before_filter :authenticate

  def authenticate
    authenticate_or_request_with_http_basic do |username, password|
      username == ENV['HTTP_USER'] && password == ENV['HTTP_PASS']
    end
  end
end

# config/initializers/dev_environment.rb
unless Rails.env.production?
  ENV['HTTP_USER'] = 'testuser'
  ENV['HTTP_PASS'] = 'testpass'
end

因此,在您的情况下,您将使用

unless Rails.env.production?
  ENV['admin_password'] = "secret"
end

不要忘记重新启动服务器,以便重新加载配置!

[旧答案]

对于应用程序范围的配置,您可以考虑以下解决方案:

创建一个包含config/application.yml要访问的选项哈希的文件:

admin_password: something_secret
allow_registration: true
facebook:
  app_id: application_id_here
  app_secret: application_secret_here
  api_key: api_key_here

现在,创建文件config/initializers/app_config.rb并包括以下内容:

require 'yaml'

yaml_data = YAML::load(ERB.new(IO.read(File.join(Rails.root, 'config', 'application.yml'))).result)
APP_CONFIG = HashWithIndifferentAccess.new(yaml_data)

现在,您可以在应用程序中的任何位置访问APP_CONFIG[:admin_password],以及所有其他数据。(请注意,由于初始化程序包括ERB.new,因此您的YAML文件可以包含ERB标记。)


2
好吧,我使用的是Heroku,它们允许您为一些不需要输入源代码控制的密码(例如密码)设置一些ENV变量。我试图找出最好的事情做我的开发机器上。是的,我正在尝试使用应用程序内部的数据。
Lan

很高兴听到!如果您认为答案是正确的,则应通过选中问题旁边的对勾标记来标记它。它将为您和答题人赢得声誉,还可以帮助以后发现此问题的人找到正确的答案。
Michelle Tilley

哦,是的,我是新用户,所以这让我等了19个小时才能进行检查。还有3小时的路程:)但是,谢谢您的所有帮助!实际上,如果您要在删除dev_environment.rb代码并将其替换为我的情况下编辑答案,那么我很乐意将您的答案标记为更加详尽。
Lan

我喜欢这个,但是由于某种原因(rails 3 v 4?)无法加载app_config.rb。我将代码放入config / environment.rb,并得到了相同的效果。#加载rails应用程序require File.expand_path('../ application',FILE)require'yaml'yaml_data = YAML :: load(ERB.new(IO.read(File.join(Rails.root,'config', 'local_env.yml'))。result)APP_CONFIG = HashWithIndifferentAccess.new(yaml_data)#初始化Rails应用程序Rails3 :: Application.initialize!

很抱歉打开这样一个旧线程,但是特定于dev环境的设置在config/environments/development.rb文件中更有意义吗?
jeffdill2

130

切勿对敏感信息(帐户凭据,密码等)进行硬编码。而是,创建一个文件来将该信息存储为环境变量(键/值对),并从源代码管理系统中排除该文件。例如,就Git(源代码管理系统)而言,可以通过将该文件添加到中来排除该文件。gitignore

-bash> echo '/config/app_environment_variables.rb' >> .gitignore 

/config/app_environment_variables.rb

ENV['HTTP_USER'] = 'devuser'
ENV['HTTP_PASS'] = 'devpass'

同样,将以下行添加到中/config/environment.rb,在该require行与该Application.initialize行之间:

# Load the app's custom environment variables here, so that they are loaded before environments/*.rb
app_environment_variables = File.join(Rails.root, 'config', 'app_environment_variables.rb')
load(app_environment_variables) if File.exists?(app_environment_variables)

而已!

就像上面的评论所说,这样做将在之前加载环境变量environments/*.rb,这意味着您将能够在这些文件(例如environments/production.rb)中引用您的变量。与将环境变量文件放入其中相比,这是一个很大的优势/config/initializers/

在内部app_environment_variables.rb,无需区分开发生产环境,因为您永远不会将此文件提交到源代码管理系统中,因此默认情况下是用于开发上下文的。但是,如果您需要为测试环境(或在本地测试生产模式的场合)设置一些特殊的东西,只需所有其他变量下面添加一个条件块:

if Rails.env.test?
  ENV['HTTP_USER'] = 'testuser'
  ENV['HTTP_PASS'] = 'testpass'
end

if Rails.env.production?
  ENV['HTTP_USER'] = 'produser'
  ENV['HTTP_PASS'] = 'prodpass'
end

每当您进行更新时app_environment_variables.rb,请重新启动应用程序服务器。假设您使用的是类似Apache / Passenger或的代码rails server

-bash> touch tmp/restart.txt

在您的代码中,请参考以下环境变量:

def authenticate
  authenticate_or_request_with_http_basic do |username, password|
    username == ENV['HTTP_USER'] && password == ENV['HTTP_PASS']
  end
end

请注意,app_environment_variables.rb您必须在内部将布尔值数字指定为字符串(例如,ENV['SEND_MAIL'] = 'false'不只是false,而ENV['TIMEOUT'] = '30'不仅仅是30),否则您将分别得到错误can't convert false into Stringcan't convert Fixnum into String

存储和共享敏感信息

最后要打结的是:如何与您的客户和/或合作伙伴共享此敏感信息?为了业务连续性(即当您被一颗流星击中时,您的客户和/或合作伙伴将如何恢复网站的全部运营?),您的客户和/或合作伙伴需要知道您的应用所需的所有凭据。通过电子邮件/ Skype处理这些事情是不安全的,并会导致混乱。将其存储在共享的Google文档中也不错(如果每个人都使用https),但是一个专用于存储和共享密码之类的小应用程序的应用程序将是理想的选择。

如何在Heroku上设置环境变量

如果您在Heroku上只有一个环境:

-bash> heroku config:add HTTP_USER='herouser'
-bash> heroku config:add HTTP_USER='heropass'

如果您在Heroku上有多个环境

-bash> heroku config:add HTTP_USER='staguser' --remote staging
-bash> heroku config:add HTTP_PASS='stagpass' --remote staging

-bash> heroku config:add HTTP_USER='produser' --remote production
-bash> heroku config:add HTTP_PASS='prodpass' --remote production

工头和.env

许多开发人员使用Foreman(与Heroku Toolbelt一起安装)在本地运行他们的应用程序(与使用Apache / Passenger或rails server)类似。Foreman和HerokuProcfile用于声明应用程序要运行的命令,因此从本地开发到Heroku的过渡是无缝的。我在每个Rails项目中都使用了Foreman和Heroku,所以这种便利非常好。但是事情就是这样。工头/.env通过dotenv加载存储在环境变量中的环境变量,但不幸的是dotenv本质上仅将文件解析为key=value成对; 这些对不会立即成为变量,所以您不能引用已经设置的变量(以使事物保持干燥),也不能在其中进行“ Ruby”操作(如上面的条件语句所述),您可以做/config/app_environment_variables.rb。例如,就保持事物干燥而言,有时我会做如下事情:

ENV['SUPPORT_EMAIL']='Company Support <support@company.com>'
ENV['MAILER_DEFAULT_FROM'] = ENV['SUPPORT_EMAIL']
ENV['MAILER_DEFAULT_TO']   = ENV['SUPPORT_EMAIL']

因此,我使用Foreman在本地运行我的应用程序,但是我不使用其.env文件来加载环境变量。而是我将Foreman与上述/config/app_environment_variables.rb方法结合使用。


3
我喜欢此解决方案,因为我想确保敏感设置(API密钥等)在密钥库中得到充分的保护,而不是以明文形式且未与Git存储库捆绑在一起。谢谢。
罗里·史丹普夫(Rori Stumpf)2012年

10

我在问题中尝试执行此操作的方式实际上有效!

# environment/development.rb

ENV['admin_password'] = "secret" 

我只需要重新启动服务器。我以为reload!在Rails控制台中运行就足够了,但我还必须重新启动Web服务器。

我选择自己的答案,因为我觉得这是放置和设置ENV变量的更好的地方


很高兴您发现了为什么它不起作用!我个人喜欢保存config/application.rbconfig/environments/*.rb设置Rails环境以及使用其他方法来设置我的应用程序环境,但这当然并不意味着这是唯一的方法(甚至是“正确的”方法:)
Michelle Tilley

我被淘汰了一点,因为我试图在生产和开发之间进行不同的设置。但是现在我完全同意你的看法!感谢您不仅回答了我的原始问题,而且还帮助我更好地了解了Rails应用程序的结构!
Lan的

8

除了这里的解决方案之外,如果您使用某些开发服务器,还有其他更清洁的选择。

使用Heroku的Foreman,您可以在.env文件中创建每个项目的环境变量:

ADMIN_PASSOWRD="secret"

使用Pow,您可以使用一个.powenv文件:

export ADMIN_PASSOWRD="secret"

2

我认为最好的方法是将它们存储在yml文件中,然后在初始化文件中使用此命令加载该文件

APP_CONFIG = YAML.load_file("#{Rails.root}/config/CONFIG.yml")[Rails.env].to_hash

您可以轻松访问与环境相关的配置变量。

您的Yml文件键值结构:

development:
  app_key: 'abc'
  app_secret: 'abc'

production:
  app_key: 'xyz'
  app_secret: 'ghq'

1

系统环境和Rails的环境是不同的东西。ENV让我们使用Rails的环境,但是如果要在运行时更改系统的环境,则可以在命令中加上反引号。

# ruby code
`export admin_password="secret"`
# more ruby code

1
只是export会抱怨空格的便条;试试export admin_password="secret"
Michelle Tilley

我忘记了(非常重要的)细节。更正了我的答案,谢谢!
goncalossilva 2011年

这不起作用,因为反引号产生了一个子shell,并且您在子shell中设置的变量不会影响父级的环境。
AndrewF

不,它确实有效。正如明确解释的那样,答案并非针对父母的环境。有非常好的答案指导如何做到这一点。
goncalossilva

1

加载自定义.env文件的脚本:在和/config/environment.rb之间添加以下行到require行之间Application.initialize

# Load the app's custom environment variables here, so that they are loaded before environments/*.rb

app_environment_variables = File.join(Rails.root, 'config', 'local_environment.env')
if File.exists?(app_environment_variables)
  lines = File.readlines(app_environment_variables)
  lines.each do |line|
    line.chomp!
    next if line.empty? or line[0] == '#'
    parts = line.partition '='
    raise "Wrong line: #{line} in #{app_environment_variables}" if parts.last.empty?
    ENV[parts.first] = parts.last
  end
end

并且config/local_environment.env(您将要.gitignore)将如下所示:

# This is ignored comment
DATABASE_URL=mysql2://user:psw@0.0.0:3307/database
RACK_ENV=development

(基于@ user664833的解决方案)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.