Có thể đặt các biến ENV cho môi trường phát triển đường ray trong mã của tôi không?


82

Tôi biết rằng tôi có thể đặt các biến ENV của mình trong bash thông qua

export admin_password = "secret"

Nhưng có cách nào để làm điều đó trong mã nguồn rails của tôi ở đâu đó không? Nỗ lực đầu tiên của tôi là một cái gì đó như thế này trongenvironment/development.rb

ENV['admin_password'] = "secret"

Nhưng nó không hoạt động. Có cách nào để làm việc này không?


Lưu ý rằng lệnh bash nên được export admin_password="secret"chứ không phải export admin_password = "secret".
Jacob Lockard

Câu trả lời:


81

[Cập nhật]

Mặc dù giải pháp trong "câu trả lời cũ" sẽ hoạt động cho các vấn đề chung, phần này là để trả lời câu hỏi cụ thể của bạn sau khi làm rõ từ nhận xét của bạn.

Bạn sẽ có thể đặt các biến môi trường chính xác như bạn chỉ định trong câu hỏi của mình. Ví dụ: tôi có một ứng dụng Heroku sử dụng xác thực cơ bản 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

Vì vậy, trong trường hợp của bạn, bạn sẽ sử dụng

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

Đừng quên khởi động lại máy chủ để cấu hình được tải lại!

[Câu trả lời cũ]

Đối với cấu hình toàn ứng dụng, bạn có thể xem xét một giải pháp như sau:

Tạo một tệp config/application.ymlvới một băm tùy chọn mà bạn muốn có thể truy cập:

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

Bây giờ, hãy tạo tệp config/initializers/app_config.rbvà bao gồm những thứ sau:

require 'yaml'

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

Giờ đây, ở bất kỳ đâu trong ứng dụng của bạn, bạn đều có thể truy cập APP_CONFIG[:admin_password]cùng với tất cả các dữ liệu khác của mình. (Lưu ý rằng vì trình khởi tạo bao gồm ERB.new, tệp YAML của bạn có thể chứa đánh dấu ERB.)


2
Chà, tôi đang sử dụng Heroku và chúng cho phép bạn đặt một số biến ENV cho những thứ như mật khẩu mà bạn không muốn kiểm tra nguồn kiểm soát. Tôi đang cố gắng tìm ra điều tốt nhất để làm trên máy phát triển của mình. Và có, tôi đang cố gắng sử dụng dữ liệu bên trong ứng dụng của mình.
Lan

Rất vui khi nghe nó! Nếu bạn cảm thấy một câu trả lời là đúng, bạn nên đánh dấu bằng cách đánh dấu vào dấu kiểm bên cạnh câu hỏi. Nó sẽ giúp bạn và người trả lời danh tiếng, đồng thời cũng giúp những người tìm thấy câu hỏi này trong tương lai tìm được câu trả lời chính xác.
Michelle Tilley

Ồ đúng rồi, tôi là người dùng mới nên tôi phải đợi 19 giờ trước khi có thể kiểm tra. Vẫn còn 3 giờ nữa để đi :) Nhưng cảm ơn vì tất cả sự giúp đỡ của bạn! Trên thực tế, nếu bạn muốn chỉnh sửa câu trả lời của mình bằng cách xóa dev_environment.rbmã và thay thế nó bằng mã của tôi, tôi sẵn lòng đánh dấu câu trả lời của bạn là kỹ lưỡng hơn nhiều.
Lan

tôi thích điều này nhưng vì một số lý do (rails 3 v 4?) không thể tải app_config.rb. Tôi đặt mã vào config / environment.rb và có ảnh hưởng tương tự. # Tải ứng dụng rails request File.expand_path ('../ application', FILE ) request 'yaml' yaml_data = YAML :: load (ERB.new (IO.read (File.join (Rails.root, 'config', 'local_env.yml'))). result) APP_CONFIG = HashWithIndierenceAccess.new (yaml_data) # Khởi tạo ứng dụng đường ray Rails3 :: Application.initialize!
Ben

Xin lỗi khi mở một chuỗi cũ như vậy nhưng cài đặt cụ thể cho môi trường nhà phát triển sẽ có ý nghĩa hơn trong config/environments/development.rbtệp sao?
jeffdill 2

130

Không bao giờ mã hóa thông tin nhạy cảm (thông tin đăng nhập tài khoản, mật khẩu, v.v.) . Thay vào đó, hãy tạo một tệp để lưu trữ thông tin đó dưới dạng các biến môi trường (cặp khóa / giá trị) và loại trừ tệp đó khỏi hệ thống quản lý mã nguồn của bạn. Ví dụ: về mặt Git (hệ thống quản lý mã nguồn), hãy loại trừ tệp đó bằng cách thêm tệp đó vào. gitignore :

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

/config/app_enosystem_variables.rb

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

Ngoài ra, hãy thêm các dòng sau vào /config/environment.rb, giữa requiredòng và Application.initializedòng:

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

Đó là nó!

Như nhận xét ở trên nói, bằng cách làm này, bạn sẽ tải các biến môi trường của mình trước environments/*.rbđó, có nghĩa là bạn sẽ có thể tham chiếu đến các biến của mình bên trong các tệp đó (ví dụ environments/production.rb). Đây là một lợi thế lớn so với việc đưa tệp biến môi trường của bạn vào bên trong /config/initializers/.

Bên trong app_environment_variables.rbkhông cần phải phân biệt môi trường là phát triển hay sản xuất bởi vì bạn sẽ không bao giờ cam kết tệp này vào hệ thống quản lý mã nguồn của mình, do đó theo mặc định , nó dành cho bối cảnh phát triển . Nhưng nếu bạn cần đặt một cái gì đó đặc biệt cho môi trường thử nghiệm (hoặc cho những trường hợp bạn thử nghiệm chế độ sản xuất cục bộ ), chỉ cần thêm một khối điều kiện bên dưới tất cả các biến khác:

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

Bất cứ khi nào bạn cập nhật app_environment_variables.rb, hãy khởi động lại máy chủ ứng dụng. Giả sử bạn đang sử dụng Apache / Passenger hoặc rails server:

-bash> touch tmp/restart.txt

Trong mã của bạn, hãy tham khảo các biến môi trường như sau:

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

Lưu ý rằng bên trong app_environment_variables.rbbạn phải chỉ định booleansố dưới dạng chuỗi (ví dụ: ENV['SEND_MAIL'] = 'false'không chỉ falseENV['TIMEOUT'] = '30'không chỉ 30), nếu không bạn sẽ nhận được lỗi can't convert false into Stringcan't convert Fixnum into Stringtương ứng.

Lưu trữ và chia sẻ thông tin nhạy cảm

Nút thắt cuối cùng để thắt chặt là: làm thế nào để chia sẻ thông tin nhạy cảm này với khách hàng và / hoặc đối tác của bạn? Vì mục đích kinh doanh liên tục (tức là khi bạn gặp phải một ngôi sao rơi, khách hàng và / hoặc đối tác của bạn sẽ tiếp tục hoạt động đầy đủ của trang web như thế nào?), Khách hàng và / hoặc đối tác của bạn cần biết tất cả thông tin đăng nhập mà ứng dụng của bạn yêu cầu . Gửi email / Skyping những thứ này xung quanh là không an toàn và dẫn đến rối loạn. Lưu trữ nó trong Google Documents được chia sẻ không phải là xấu (nếu tất cả mọi người đều sử dụng https), nhưng một ứng dụng dành riêng để lưu trữ và chia sẻ các mẩu tin nhỏ như mật khẩu sẽ là lý tưởng.

Cách đặt biến môi trường trên Heroku

Nếu bạn có một môi trường duy nhất trên Heroku:

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

Nếu bạn có nhiều môi trường trên 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

Quản đốc và .env

Nhiều nhà phát triển sử dụng Foreman (được cài đặt với Heroku Toolbelt ) để chạy các ứng dụng của họ cục bộ (trái ngược với việc sử dụng các ứng dụng như Apache / Passenger hoặc rails server). Foreman và Heroku sử dụng Procfileđể khai báo những lệnh nào được chạy bởi ứng dụng của bạn , vì vậy việc chuyển đổi từ local dev sang Heroku là liền mạch về mặt đó. Tôi sử dụng Foreman và Heroku trong mọi dự án Rails, vì vậy sự tiện lợi này là rất tốt. Nhưng đây là vấn đề .. Foreman tải các biến môi trường được lưu trữ trong /.envdotenv nhưng thật không may dotenv về cơ bản chỉ phân tích cú pháp tệp cho key=valuecác cặp; những cặp đó không trở thành biến ngay tại đó và sau đó, vì vậy bạn không thể tham chiếu đến các biến đã đặt (để giữ cho mọi thứ KHÔ), cũng như bạn không thể làm "Ruby" trong đó (như đã lưu ý ở trên với các điều kiện), bạn có thể làm trong /config/app_environment_variables.rb. Ví dụ, về việc giữ cho mọi thứ KHÔ, đôi khi tôi làm những việc như sau:

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

Do đó, tôi sử dụng Foreman để chạy các ứng dụng của mình cục bộ, nhưng tôi không sử dụng .envtệp của nó để tải các biến môi trường; đúng hơn là tôi sử dụng Foreman kết hợp với /config/app_environment_variables.rbcách tiếp cận được mô tả ở trên.


3
Tôi thích giải pháp này vì tôi muốn đảm bảo rằng các cài đặt nhạy cảm (khóa API, v.v.) được bảo vệ đầy đủ trong kho khóa, thay vì ở dạng văn bản rõ ràng và không được đóng gói với kho lưu trữ Git. Cảm ơn.
Rori Stumpf 4/10/12

10

Cách tôi đang cố gắng thực hiện điều này trong câu hỏi của tôi thực sự hoạt động!

# environment/development.rb

ENV['admin_password'] = "secret" 

Tôi vừa phải khởi động lại máy chủ. Tôi nghĩ rằng chạy reload!trong bảng điều khiển rails là đủ nhưng tôi cũng phải khởi động lại máy chủ web.

Tôi đang chọn câu trả lời của riêng mình vì tôi cảm thấy đây là nơi tốt hơn để đặt và đặt các biến ENV


Rất vui vì bạn đã tìm ra lý do tại sao nó không hoạt động! Cá nhân tôi thích lưu config/application.rbconfig/environments/*.rbđể thiết lập môi trường Rails và sử dụng các phương pháp khác để thiết lập môi trường ứng dụng của mình , nhưng điều đó chắc chắn không có nghĩa đó là cách duy nhất (hoặc thậm chí là cách "đúng" :)
Michelle Tilley

Tôi đã bị bỏ rơi một chút vì tôi đang cố gắng thiết lập mọi thứ khác nhau giữa sản xuất và phát triển. Nhưng bây giờ tôi hoàn toàn đồng ý với bạn! Cảm ơn vì không chỉ trả lời câu hỏi ban đầu của tôi mà còn giúp tôi hiểu cấu trúc ứng dụng rails tốt hơn!
Lan

8

Ngoài các giải pháp ở đây, có các giải pháp thay thế sạch hơn nếu bạn đang sử dụng các máy chủ phát triển nhất định.

Với Heroku's Foreman , bạn có thể tạo các biến môi trường cho mỗi dự án trong một .envtệp:

ADMIN_PASSOWRD="secret"

Với Pow , bạn có thể sử dụng .powenvtệp:

export ADMIN_PASSOWRD="secret"

2

Tôi nghĩ cách tốt nhất là lưu trữ chúng trong một số tệp yml và sau đó tải tệp đó bằng lệnh này trong tệp intializer

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

bạn có thể dễ dàng truy cập các biến cấu hình liên quan đến môi trường.

Cấu trúc giá trị khóa tệp Yml của bạn:

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

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

1

Môi trường hệ thống và môi trường đường ray là những thứ khác nhau. ENVcho phép bạn làm việc với môi trường của đường ray, nhưng nếu điều bạn muốn làm là thay đổi môi trường của hệ thống trong thời gian chạy, bạn có thể chỉ cần bao quanh lệnh bằng các dấu gạch ngược.

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

1
Chỉ cần một ghi chú exportsẽ phàn nàn về không gian; thửexport admin_password="secret"
Michelle Tilley

Tôi đã quên chi tiết (rất quan trọng) đó. Đã sửa câu trả lời của tôi, cảm ơn!
goncalossilva

Điều này không hoạt động vì các dấu gạch ngược tạo ra một vỏ con và các biến bạn đặt trong vỏ con không thể ảnh hưởng đến môi trường của chính.
AndrewF

Không, nó hoạt động. Câu trả lời, như đã giải thích rõ ràng, không nhắm vào môi trường của phụ huynh. Có những câu trả lời hoàn toàn tốt hướng dẫn cách làm điều đó.
goncalossilva

1

Tập lệnh tải .envtệp tùy chỉnh : Thêm các dòng sau vào /config/environment.rb, giữa requiredòng và Application.initializedòng:

# 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(bạn sẽ muốn .gitignorenó) sẽ giống như sau:

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

(Dựa trên giải pháp của @ user664833)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.