无法为 nil:NilClass 加载"rails.application.database_configuration"未定义方法"[]"



我更改了我的database.yml,在测试和开发中使用sqlite3数据库,在生产中使用postgresql。我的应用程序在生产中运行良好,但当我启动测试或开发环境时,我会出现以下错误:

Cannot load 'Rails.application.database_configuration':
undefined method'[]' for nil:NilClass (NoMethoError)

我的数据库yml:

# SQLite version 3.x
#   gem install sqlite3
#
#   Ensure the SQLite 3 gem is defined in your Gemfile
#   gem 'sqlite3'
#
default: &default
  adapter: sqlite3
  pool: 5
  timeout: 5000
development:
  <<: *default
  database: db/development.sqlite3
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: db/test.sqlite3
production:
  pool: 5
  timeout: 5000
  encoding: utf8
  adapter: postgresql
  host: <%= Rails.application.secrets[:database][:host]%>
  database: <%= Rails.application.secrets[:database][:name]%>
  username: <%= Rails.application.secrets[:database][:username]%>
  password: <%= Rails.application.secrets[:database][:password]%>

在新的Rails 5.1.0中运行,并在新的secret加密文件中添加了我的变量。

你的nil之所以发生,是因为即使它是在开发中,它仍然试图加载所有内容,而你正在从nil调用东西->something[:nil][cant_grab_from_nil]。快速解决方法是if语句。只有在新的Rails5.1中使用secrets加密文件时才建议这样做。

production:
  pool: 5
  timeout: 5000
  encoding: utf8
  adapter: postgresql
  <% if Rails.application.secrets[:database].present? %>
    host: <%= Rails.application.secrets[:database][:host]%>
    database: <%= Rails.application.secrets[:database][:name]%>
    username: <%= Rails.application.secrets[:database][:username]%>
    password: <%= Rails.application.secrets[:database][:password]%>
  <% end %>

关于安全

如果你要走这条路,这很好,你需要确保一件非常重要的事情:

您的secrets.yml文件是安全配置的,没有检查到源代码管理中,任何不应该访问

在这种情况下,它的安全性不亚于为您的web服务器锁定*key/*crt证书文件,除非您可能存储多个机密。正确地执行比将机密放入ENV更可取,但仍有更好的选择。

进一步阅读:

  • http://movingfast.io/articles/environment-variables-considered-harmful/
  • http://elasticcompute.io/2016/01/21/runtime-secrets-with-docker-containers/(obvs忽略Docker特定的内容)

您的实际问题

你的问题是@tagCincy的第二个想法("b"),奇怪的是,这非常容易解决。按照@Nik Olai的建议去做。在您的开发/测试环境中声明(尽管为空)相同参数的值,如下所示:

development:
  ...
  database:
    :name:
    :username:
    :password:
test:
  # same thing here

原因是,虽然production数据库配置没有在developmenttest环境中使用,但该配置的解析仍然会发生。

换句话说,即使在测试/开发模式下,生产数据库设置仍然会被解析(并解释ERB)。

Rails.application.secrets依赖于环境,因此在开发和测试模式下,Rails.application.secrets[:database]将不存在,这意味着后续的[]调用将达到零目标,瞧!

host: <%= Rails.application.secrets[:database][:host]%>
database: <%= Rails.application.secrets[:database][:name]%>
username: <%= Rails.application.secrets[:database][:username]%>
password: <%= Rails.application.secrets[:database][:password]%>

天啊,别这样。不要这样做有很多原因。

在生产服务器上使用ENV vars:

host: <%= ENV['DB_HOST'] %>
database: <%= ENV['DB_NAME'] %>
username: <%= ENV['DB_USER'] %>
password: <%= ENV['DB_PASSEWORD'] %>

然后,您需要进入prod服务器,在shell配置文件(.bashrc、.zshrc、.profile)中设置这些变量,如下所示:

export DB_HOST=your_host
export DB_NAME=your_name
export DB_USER=your_user
export DB_PASSWORD=your_password

你的问题是2件可能的事情之一:

a。在机密文件之前加载数据库配置的竞争条件。

b。您已经将secrets.yml划分为环境,而没有用于开发/测试环境的节点。

相关内容

最新更新