创建Rails应用程序的自定义配置选项的最佳方法是什么?

132

我需要为我的Rails应用程序创建一个配置选项。它可以在所有环境中保持一致。我发现如果我在environment.rb中设置它,它就可以在我的视图中使用,这正是我想要的...

environment.rb

AUDIOCAST_URI_FORMAT = http://blablalba/blabbitybla/yadda

效果很好。

然而,我有点不安。这是一个好方法吗?是否有更时髦的方式?

14个回答

194

对于不需要存储在数据库表中的一般应用配置,我喜欢在config目录下创建一个config.yml文件。对于您的示例,它可能如下所示:

defaults: &defaults
  audiocast_uri_format: http://blablalba/blabbitybla/yadda

development:
  <<: *defaults

test:
  <<: *defaults

production:
  <<: *defaults

这个配置文件是从 config/initializers 的自定义初始化中加载的:

# Rails 2
APP_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/config.yml")[RAILS_ENV]

# Rails 3+
APP_CONFIG = YAML.load_file(Rails.root.join('config/config.yml'))[Rails.env]

如果你在使用Rails 3,确保不要意外地在相对配置路径前添加斜杠。

然后,你可以使用以下代码检索值:

uri_format = APP_CONFIG['audiocast_uri_format']

查看这个Railscast获取完整细节。


1
你可能需要 YAML::ENGINE.yamler = 'syck' 才能使其正常工作。https://dev59.com/pVfUa4cB1Zd3GeqPJpsi#6140900 - evanrmurphy
45
仅供参考,对于Rails 3.x版本,您需要将RAILS_ENV替换为Rails.env,将RAILS_ROOT替换为Rails.root - JeanMertz
5
对于Rails 3+,你应该使用相对路径而不是绝对路径进行连接。不要在配置目录前加斜杠。 - wst
10
在Rails 4.1中,你可以使用Rails.application.config.whatever_you_want = YAML.load_file(Rails.root.join('config', 'config.yml'))[Rails.env]这个语句,但我不确定之前版本是否可行。该语句的功能是将配置文件中的信息加载到Rails应用程序的配置中,并根据当前运行环境选择相应的配置信息。 - d4rky
2
@iphone007,确实可以从配置目录加载任意的yaml文件。请参见下面smathy的答案,我认为现在应该接受这个答案。 - omnikron
显示剩余4条评论

82

Rails 3版本的初始化器代码如下(RAILS_ROOT和RAILS_ENV已被弃用)

APP_CONFIG = YAML.load_file(Rails.root.join('config', 'config.yml'))[Rails.env]

此外,Ruby 1.9.3使用Psych,使合并键区分大小写,因此您需要更改配置文件以考虑这一点,例如:

defaults: &DEFAULTS
  audiocast_uri_format: http://blablalba/blabbitybla/yadda

development:
  <<: *DEFAULTS

test:
  <<: *DEFAULTS

production:
  <<: *DEFAULTS

3
不需要使用 "#{Rails.root.to_s}""#{Rails.root}" 就可以了。 - David J.
3
我建议使用 Rails.root.join('config', 'config.yml') 而不是 "#{Rails.root.to_s}/config/config.yml" - David J.
2
而且,我建议使用 AppName::Application.config.custom 替代 APP_CONFIG。 - David J.
1
David,你的前两个评论是最佳实践,我会修改代码,但最后一个评论我会忽略,因为这意味着你需要记得每次使用此代码时更改AppName。 - David Burrows

61

Rails >= 4.2

只需在config/目录中创建一个YAML文件,例如:config/neo4j.yml

neo4j.yml的内容可以像下面这样(为了简化起见,我在所有环境中都使用默认值):

default: &default
  host: localhost
  port: 7474
  username: neo4j
  password: root

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default

config/application.rb文件中:

module MyApp
  class Application < Rails::Application
    config.neo4j = config_for(:neo4j)
  end
end

现在,您的自定义配置可以像下面这样访问:

Rails.configuration.neo4j['host'] #=>localhost
Rails.configuration.neo4j['port'] #=>7474

更多信息

Rails官方API文档将config_for方法描述为:

方便地为当前的Rails环境加载config/foo.yml


如果您不想使用yaml文件

如Rails官方指南所述:

您可以通过自定义配置在Rails配置对象下的config.x属性来配置自己的代码。

示例

config.x.payment_processing.schedule = :daily
config.x.payment_processing.retries  = 3
config.x.super_debugger = true

这些配置点随后可以通过配置对象访问:

Rails.configuration.x.payment_processing.schedule # => :daily
Rails.configuration.x.payment_processing.retries  # => 3
Rails.configuration.x.super_debugger              # => true
Rails.configuration.x.super_debugger.not_set      # => nil

config_for方法的官方参考文档 | Rails官方指南


25

步骤1:创建 config/initializers/appconfig.rb 文件。

require 'ostruct'
require 'yaml'

all_config = YAML.load_file("#{Rails.root}/config/config.yml") || {}
env_config = all_config[Rails.env] || {}
AppConfig = OpenStruct.new(env_config)

步骤2:创建config/config.yml

common: &common
  facebook:
    key: 'asdjhasxas'
    secret : 'xyz'
  twitter:
    key: 'asdjhasxas'
    secret : 'abx'

development:
  <<: *common

test:
  <<: *common

production:
  <<: *common

步骤 3: 在代码中任意获取常量

facebook_key = AppConfig.facebook['key']
twitter_key  = AppConfig.twitter['key']

我们如何在config.yml中读取环境变量?我的配置是相同的,我已经在bashrc中添加了变量,并尝试使用key:<%= ENV[URL] %>在config.yml中读取它,但这并不起作用。 - shiva
@shiva 请查看Figaro gem以获取ENV变量。此配置设置适用于不需要隐藏在源代码控制中的值。 - Shadoath

17

我只是想为Rails 4.2和5中最新的酷炫功能更新做一个说明,现在您可以在任何config/**/*.rb文件中执行此操作:

config.x.whatever = 42

(这里的 x 是字面意义上的,也就是说,config.x. 必须是字面意义上的 x,然后你可以在 x 后面添加任何内容)

...然后在你的应用程序中可用的形式为:

Rails.configuration.x.whatever

查看更多内容:http://guides.rubyonrails.org/configuring.html#custom-configuration


3
需要澄清一点,最初导致我困惑的是,x不是一个可以随意替换的占位符,它实际上必须是字母 x - tobinibot
非常好的观点@tobinibot - 我已经在我的答案中添加了那个澄清,谢谢。 - smathy
有趣的是,指南实际上没有提到'x',但我可以证明,在Rails 5.0中仍然是必要的。 - Don
你说得对,唐,这很奇怪 - 我确定它以前是这样说的。 - smathy
希望这能为某人节省一些精力,但是要实现自动加载,我必须将config.x的内容放在config/initializers/<myappname>.rb中。其中myappname是包含在config/application.rb中的模块名称。然后,您需要执行Myappname::Application.config.x.something = 'something'。 - Andy Fraley
1
从当前的Rails文档中:您可以通过Rails配置对象配置自己的代码,使用config.x命名空间或直接使用config进行自定义配置。这两者之间的关键区别在于,如果您正在定义嵌套配置(例如:config.x.nested.nested.hi),则应该使用config.x,而对于单层配置(例如:config.hello),则只需使用config。来源:https://guides.rubyonrails.org/configuring.html#custom-configuration - David Gay

6

这个主题还有一些额外的信息:

APP_CONFIG = YAML.load_file(Rails.root.join('config', 'config.yml'))[Rails.env].with_indifferent_access

".with_indifferent_access"允许您使用字符串键或等效的符号键访问散列中的值。
例如:
APP_CONFIG['audiocast_uri_format'] => 'http://blablalba/blabbitybla/yadda' APP_CONFIG[:audiocast_uri_format] => 'http://blablalba/blabbitybla/yadda' 这只是方便之举,但我更喜欢将我的键表示为符号。

5
我使用类似于 John 的方法来处理 Rails 3.0/3.1 中的问题,不过我先用 erb 解析文件:
APP_CONFIG = YAML.load(ERB.new(File.new(File.expand_path('../config.yml', __FILE__)).read).result)[Rails.env]

这使我能够在需要时在我的配置中使用ERB,比如读取Heroku的Redistogo URL:
production:
  <<: *default
  redis:                  <%= ENV['REDISTOGO_URL'] %>

2
我不认为我每天都需要这个,但在你需要它的时候,这是一个非常棒的解决方案。我想我会把文件名改为config.yml.erb以符合Rails约定。 - Andrew Burns

2

Rails 4

创建一个自定义配置yaml文件,并加载它(并让它对你的应用程序可用),类似于database_configuration

创建你的*.yml文件,我需要一个redis配置文件。

config/redis.yml

default: &default
  host: localhost
  port: 6379

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default
  host: <%= ENV['ELASTICACHE_HOST'] %>
  port: <%= ENV['ELASTICACHE_PORT'] %>

然后加载配置文件。 config/application.rb
module MyApp
  class Application < Rails::Application

    ## http://guides.rubyonrails.org/configuring.html#initialization-events
    config.before_initialize do
      Rails.configuration.redis_configuration = YAML.load_file("#{Rails.root}/config/redis.yml")
    end

  end
end

访问值:

Rails.configuration.redis_configuration[Rails.env] 类似于您可以通过 Rails.configuration.database_configuration[Rails.env] 访问 database.yml


你也可以节省一些时间,只需获取当前环境的设置,这些设置可能是你唯一需要的:Rails.configuration.redis_configuration = YAML.load_file("#{Rails.root}/config/redis.yml")[Rails.env]。然而,在Rails 4.2及以上版本中,smathy的答案可能是更简单的方法。 - omnikron

1

在Omer Aslam优雅的解决方案基础上,我决定将键转换为符号。唯一的改变是:

all_config = YAML.load_file("#{Rails.root}/config/config.yml").with_indifferent_access || {}

这样可以让你通过符号作为键来引用值,例如:
AppConfig[:twitter][:key]

在我看来,这样更整洁。

(由于我的声望不够高,无法在Omer的回复中发表评论,因此作为答案发布)


0

我更喜欢通过全局应用程序堆栈访问设置。我避免在本地作用域中使用过多的全局变量。

config/initializers/myconfig.rb

MyAppName::Application.define_singleton_method("myconfig") {YAML.load_file("#{Rails.root}/config/myconfig.yml") || {}}

并通过访问它。

MyAppName::Application.myconfig["yamlstuff"]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接