¿Es posible establecer variables ENV para el entorno de desarrollo de rieles en mi código?

82

Sé que puedo configurar mis variables ENV en bash a través de

export admin_password = "secret"

Pero, ¿hay alguna manera de hacerlo en el código fuente de mis rieles en alguna parte? Mi primer intento fue algo como esto enenvironment/development.rb

ENV['admin_password'] = "secret"

Pero no funcionó. ¿Hay alguna forma de hacer esto?

Lan
fuente
Tenga en cuenta que el comando bash debería ser export admin_password="secret", no export admin_password = "secret".
Jacob Lockard

Respuestas:

81

[Actualizar]

Si bien la solución en "respuesta anterior" funcionará para problemas generales, esta sección es para responder su pregunta específica después de la aclaración de su comentario.

Debería poder establecer variables de entorno exactamente como lo especifica en su pregunta. Como ejemplo, tengo una aplicación Heroku que usa autenticación básica HTTP.

# 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

Entonces en tu caso usarías

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

¡No olvide reiniciar el servidor para que se vuelva a cargar la configuración!

[Respuesta anterior]

Para la configuración de toda la aplicación, puede considerar una solución como la siguiente:

Cree un archivo config/application.ymlcon un hash de opciones a las que desea poder acceder:

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

Ahora, cree el archivo config/initializers/app_config.rbe incluya lo siguiente:

require 'yaml'

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

Ahora, en cualquier lugar de su aplicación, puede acceder APP_CONFIG[:admin_password], junto con todos sus demás datos. (Tenga en cuenta que, dado que el inicializador incluye ERB.new, su archivo YAML puede contener marcado ERB).

Michelle Tilley
fuente
2
Bueno, estoy usando Heroku y te permiten establecer algunas variables ENV para cosas como contraseñas que no quieres que se registren en el control de fuente. Estoy tratando de averiguar qué es lo mejor que puedo hacer en mi máquina de desarrollo. Y sí, estoy tratando de usar los datos dentro de mi aplicación.
Lan
¡Alegra oírlo! Si cree que una respuesta es correcta, debe marcarla marcando la marca de verificación junto a la pregunta. Le hará ganar reputación a usted y al respondedor y también ayudará a las personas que encuentren esta pregunta en el futuro a encontrar la respuesta correcta.
Michelle Tilley
Oh, sí, soy un usuario nuevo, así que me está haciendo esperar 19 horas antes de poder verificarlo. Aún quedan 3 horas más :) ¡Pero gracias por toda su ayuda! En realidad, si editara su respuesta eliminando el dev_environment.rbcódigo y reemplazándolo con el mío, con mucho gusto marcaría su respuesta, que es mucho más completa.
Lan
Me gusta esto, pero por alguna razón (¿rieles 3 v 4?) No pude cargar app_config.rb. Puse el código en config / environment.rb y obtuve el mismo efecto. # Cargar la aplicación 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'))). resultado) APP_CONFIG = HashWithIndifferentAccess.new (yaml_data) # Inicializar la aplicación rails Rails3 :: Application.initialize!
Ben
Lamento abrir un hilo tan antiguo, pero ¿no tendría más sentido una configuración específica del entorno de desarrollo en el config/environments/development.rbarchivo?
jeffdill2
130

Nunca codifique información confidencial (credenciales de cuenta, contraseñas, etc.) . En su lugar, cree un archivo para almacenar esa información como variables de entorno (pares clave / valor) y excluya ese archivo de su sistema de administración de código fuente. Por ejemplo, en términos de Git (sistema de administración de código fuente), excluya ese archivo agregándolo a. gitignore :

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

/config/app_environment_variables.rb

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

Además, agregue las siguientes líneas /config/environment.rbentre la requirelínea y la Application.initializelínea:

# 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)

¡Eso es!

Como dice el comentario anterior, al hacer esto, estará cargando sus variables de entorno antes environments/*.rb, lo que significa que podrá hacer referencia a sus variables dentro de esos archivos (por ejemplo environments/production.rb). Esta es una gran ventaja sobre poner su archivo de variables de entorno dentro /config/initializers/.

En el interior app_environment_variables.rbno es necesario distinguir los entornos en cuanto a desarrollo o producción porque nunca enviará este archivo a su sistema de gestión de código fuente, por lo que es para el contexto de desarrollo de forma predeterminada. Pero si necesita establecer algo especial para el entorno de prueba (o para ocasiones en las que prueba el modo de producción localmente ), simplemente agregue un bloque condicional debajo de todas las demás variables:

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

Siempre que actualice app_environment_variables.rb, reinicie el servidor de aplicaciones. Suponiendo que está utilizando Apache / Passenger o rails server:

-bash> touch tmp/restart.txt

En su código, consulte las variables de entorno de la siguiente manera:

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

Tenga en cuenta que dentro app_environment_variables.rbdebe especificar booleanos y números como cadenas (por ejemplo, ENV['SEND_MAIL'] = 'false'no solo false, y ENV['TIMEOUT'] = '30'no solo 30), de lo contrario obtendrá los errores can't convert false into Stringy can't convert Fixnum into String, respectivamente.

Almacenar y compartir información confidencial

El nudo final a atar es: ¿cómo compartir esta información sensible con sus clientes y / o socios? Con el fin de la continuidad del negocio (es decir, cuando te golpea una estrella fugaz, ¿cómo reanudarán tus clientes y / o socios las operaciones completas del sitio?), Tus clientes y / o socios deben conocer todas las credenciales requeridas por tu aplicación. . Enviar por correo electrónico / Skype estas cosas es inseguro y conduce al desorden. Almacenarlo en Google Docs compartido no está mal (si todos usan https), pero una aplicación dedicada a almacenar y compartir pequeños detalles como contraseñas sería ideal.

Cómo configurar variables de entorno en Heroku

Si tiene un solo entorno en Heroku:

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

Si tiene varios entornos en 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

Foreman y .env

Muchos desarrolladores usan Foreman (instalado con Heroku Toolbelt ) para ejecutar sus aplicaciones localmente (en lugar de usar Apache / Passenger o rails server). Foreman y Heroku utilizan Procfilepara declarar qué comandos ejecuta su aplicación , por lo que la transición del desarrollador local a Heroku es perfecta en ese sentido. Utilizo Foreman y Heroku en todos los proyectos de Rails, por lo que esta conveniencia es excelente. Pero aquí está la cuestión ... Foreman carga las variables de entorno almacenadas a /.envtravés de dotenv pero, lamentablemente, dotenv esencialmente solo analiza el archivo en busca de key=valuepares; esos pares no se convierten en variables allí mismo, por lo que no puede hacer referencia a las variables ya configuradas (para mantener las cosas SECAS), ni puede hacer "Ruby" allí (como se señaló anteriormente con los condicionales), que puede hacer en /config/app_environment_variables.rb. Por ejemplo, en términos de mantener las cosas SECAS, a veces hago cosas como esta:

ENV['SUPPORT_EMAIL']='Company Support <[email protected]>'
ENV['MAILER_DEFAULT_FROM'] = ENV['SUPPORT_EMAIL']
ENV['MAILER_DEFAULT_TO']   = ENV['SUPPORT_EMAIL']

Por lo tanto, uso Foreman para ejecutar mis aplicaciones localmente, pero no uso su .envarchivo para cargar variables de entorno; en lugar de eso, utilizo Foreman junto con el /config/app_environment_variables.rbenfoque descrito anteriormente.

usuario664833
fuente
3
Me gusta esta solución porque quería asegurarme de que las configuraciones confidenciales (claves API, etc.) estén adecuadamente protegidas en un almacén de claves, en lugar de en texto claro y no incluidas en el repositorio de Git. Gracias.
Rori Stumpf
10

¡La forma en que estoy tratando de hacer esto en mi pregunta realmente funciona!

# environment/development.rb

ENV['admin_password'] = "secret" 

Solo tuve que reiniciar el servidor. Pensé que ejecutar reload!en la consola rails sería suficiente, pero también tuve que reiniciar el servidor web.

Estoy eligiendo mi propia respuesta porque siento que este es un mejor lugar para colocar y configurar las variables ENV

Lan
fuente
¡Me alegra que hayas descubierto por qué no funcionaba! Personalmente, me gusta guardar config/application.rby config/environments/*.rbconfigurar el entorno Rails y usar otros métodos para configurar el entorno de mi aplicación , pero eso ciertamente no significa que sea la única forma (o incluso la forma "correcta" :)
Michelle Tilley
Estaba un poco desconcertado porque estaba tratando de establecer las cosas de manera diferente entre producción y desarrollo. ¡Pero ahora estoy completamente de acuerdo contigo! ¡Gracias no solo por responder mi pregunta original, sino también por ayudarme a comprender mejor la estructura de la aplicación Rails!
Lan
8

Aparte de las soluciones aquí, existen alternativas más limpias si está utilizando ciertos servidores de desarrollo.

Con Foreman de Heroku , puede crear variables de entorno por proyecto en un .envarchivo:

ADMIN_PASSOWRD="secret"

Con Pow , puede utilizar un .powenvarchivo:

export ADMIN_PASSOWRD="secret"
Aupajo
fuente
2

Creo que la mejor manera es almacenarlos en algún archivo yml y luego cargar ese archivo usando este comando en el archivo inicializador.

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

puede acceder fácilmente a las variables de configuración relacionadas con el entorno.

Su estructura de valor de clave de archivo Yml:

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

production:
  app_key: 'xyz'
  app_secret: 'ghq'
Taimoor Changaiz
fuente
1

El entorno del sistema y el entorno de los rieles son cosas diferentes. ENVle permite trabajar con el entorno de los rieles, pero si lo que quiere hacer es cambiar el entorno del sistema en tiempo de ejecución, puede rodear el comando con comillas invertidas.

# ruby code
`export admin_password="secret"`
# more ruby code
Goncalossilva
fuente
1
Solo una nota que exportse quejará de los espacios; probarexport admin_password="secret"
Michelle Tilley
Olvidé ese (muy importante) detalle. Corregí mi respuesta, ¡gracias!
goncalossilva
Esto no funciona ya que las comillas invertidas generan una subcapa y las variables que estableces en la subcapa no pueden afectar el entorno del padre.
AndrewF
No, funciona. La respuesta, como se explica claramente, no está dirigida al entorno de los padres. Hay respuestas perfectamente buenas que enseñan cómo hacerlo.
goncalossilva
1

Script para cargar un .envarchivo personalizado : agregue las siguientes líneas /config/environment.rbentre la requirelínea y la Application.initializelínea:

# 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

Y config/local_environment.env(lo querrás .gitignore) se verá así:

# This is ignored comment
DATABASE_URL=mysql2://user:[email protected]:3307/database
RACK_ENV=development

(Basado en la solución de @ user664833)

Daniel Garmoshka
fuente