Чи можна встановити змінні ENV для середовища розробки рейок у моєму коді?


83

Я знаю, що я можу встановити свої змінні ENV в bash через

export admin_password = "secret"

Але чи є спосіб це зробити у моєму вихідному коді rails? Моя перша спроба була приблизно такою уenvironment/development.rb

ENV['admin_password'] = "secret"

Але це не спрацювало. Чи є спосіб зробити це?


1
Зверніть увагу, що команда bash повинна бути export admin_password="secret", а не export admin_password = "secret".
Jacob Lockard

Відповіді:


81

[Оновлення]

Хоча рішення під "старою відповіддю" буде працювати для загальних проблем, цей розділ має відповісти на ваше конкретне питання після роз'яснення з вашого коментаря.

Ви повинні мати можливість встановлювати змінні середовища точно так, як ви вказали у своєму питанні. Як приклад, у мене є програма Heroku, яка використовує базову автентифікацію 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

Тож у вашому випадку ви б використали

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 для таких речей, як паролі, які ви не хочете перевіряти в контролі джерела. Я намагаюся зрозуміти, що найкраще зробити на моїй розробницькій машині. І так, я намагаюся використовувати дані всередині мого додатка.
Лан

Радий це чути! Якщо ви вважаєте, що відповідь правильна, позначте її, поставивши галочку біля запитання. Це принесе вам і репутації відповідача відповідь, а також допоможе людям, які знайдуть це питання в майбутньому, знайти правильну відповідь.
Мішель Тіллі

О так, я новий користувач, тож змушує почекати 19 годин, перш ніж я зможу це перевірити. Залишилося ще 3 години :) Але дякую за всю допомогу! Насправді, якщо ви відредагуєте свою відповідь, видаливши dev_environment.rbкод і замінивши його на мій, я із задоволенням позначу вашу відповідь, яка є набагато більш ретельною.
Лан

мені це подобається, але з якихось причин (rails 3 v 4?) не вдалося завантажити app_config.rb. Я помістив код у config / environment.rb і отримав той самий ефект. # Для завантаження програми rails потрібно File.expand_path ('../ application', FILE ) require 'yaml' yaml_data = YAML :: load (ERB.new (IO.read (File.join (Rails.root, 'config', 'local_env.yml'))). результат) APP_CONFIG = HashWithIndifferentAccess.new (yaml_data) # Ініціалізуйте додаток Rails Rails3 :: Application.initialize!
Бен

Вибачте, що відкрив такий старий потік, але чи не має параметр, характерний для середовища розробника, більше сенсу у 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 Stringі can't convert Fixnum into String, відповідно.

Зберігання та обмін конфіденційною інформацією

Останній вузол: як поділитися цією конфіденційною інформацією зі своїми клієнтами та / або партнерами? З метою безперервності бізнесу (тобто, коли вас вразить падаюча зірка, як ваші клієнти та / або партнери відновлять повноцінну роботу сайту?), Ваші клієнти та / або партнери повинні знати всі дані, необхідні вашому додатку . Надсилання електронної пошти / скайпінг цих речей небезпечно і веде до безладу. Зберігати його у спільних документах 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). Форман та Heroku використовують Procfileдля декларування того, які команди запускає ваш додаток , тому перехід від локального розробника до Heroku є плавним у цьому відношенні. Я використовую Foreman та Heroku у кожному проекті Rails, тому ця зручність чудова. Але ось у чому річ .. Форман завантажує змінні середовища, що зберігаються в /.envчерез dotenv, але, на жаль, dotenv по суті аналізує файл лише для key=valueпар; ці пари не стають змінними тут же і тоді, тому ви не можете посилатися на вже встановлені змінні (щоб зберегти сухі речі), а також не можете робити там "Рубін" (як зазначено вище з умовними умовами), який ви можете робити в /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. Дякую.
Рорі Штумпф,

10

Те, як я намагаюся зробити це у своєму питанні, насправді працює!

# environment/development.rb

ENV['admin_password'] = "secret" 

Мені просто довелося перезапустити сервер. Я думав, що роботи reload!в консолі rails буде достатньо, але мені також довелося перезапустити веб-сервер.

Я вибираю власну відповідь, тому що вважаю, що це краще місце для встановлення та встановлення змінних ENV


Радий, що ти дізнався, чому це не працює! Мені особисто подобається економити config/application.rbта config/environments/*.rbналаштовувати середовище Rails та використовувати інші методи для налаштування мого середовища програми , але це, безумовно, не означає, що це єдиний спосіб (або навіть "правильний" спосіб :)
Мішель Тіллі,

Мене трохи відкинуло, тому що я намагався встановити щось інше між виробництвом та розробкою. Але зараз я повністю з вами згоден! Дякуємо, що не лише відповіли на моє оригінальне запитання, але допомогли мені краще зрозуміти структуру програми rails!
Лан

8

Окрім рішень тут, є чистіші альтернативи, якщо ви використовуєте певні сервери розробки.

За допомогою Heroku's 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

Системне середовище та середовище рейок - це різні речі. ENVдавайте працювати з середовищем рейок, але якщо ви хочете змінити середовище системи під час виконання, ви можете просто оточити команду зворотними позначками.

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

1
Просто примітка, яка exportбуде скаржитися на пробіли; спробуватиexport admin_password="secret"
Мішель Тіллі

Я забув цю (дуже важливу) деталь. Виправив свою відповідь, дякую!
goncalossilva

Це не спрацьовує, оскільки зворотні позначки породжують під оболонку, а змінні, встановлені в під оболонці, не можуть впливати на оточення батьків.
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)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.