133

I need to create one config option for my Rails application. It can be the same for all environments. I found that if I set it in environment.rb, it's available in my views, which is exactly what I want...

environment.rb

AUDIOCAST_URI_FORMAT = http://blablalba/blabbitybla/yadda

Works great.

However, I'm a little uneasy. Is this a good way to do it? Is there a way that's more hip?

Ethan
  • 57,819
  • 63
  • 187
  • 237

14 Answers14

195

For general application configuration that doesn't need to be stored in a database table, I like to create a config.yml file within the config directory. For your example, it might look like this:

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

development:
  <<: *defaults

test:
  <<: *defaults

production:
  <<: *defaults

This configuration file gets loaded from a custom initializer in 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]

If you're using Rails 3, ensure you don't accidentally add a leading slash to your relative config path.

You can then retrieve the value using:

uri_format = APP_CONFIG['audiocast_uri_format']

See this Railscast for full details.

mplewis
  • 464
  • 1
  • 8
  • 18
John Topley
  • 113,588
  • 46
  • 195
  • 237
  • 1
    You may need `YAML::ENGINE.yamler = 'syck'` for this to work http://stackoverflow.com/a/6140900/414220 – evanrmurphy Mar 20 '12 at 21:59
  • 45
    Just a FYI, in Rails 3.x you need to replace `RAILS_ENV` with `Rails.env` and `RAILS_ROOT` with `Rails.root`. – JeanMertz Apr 13 '12 at 10:15
  • There is a good railscast explaining this: http://railscasts.com/episodes/85-yaml-configuration-file – Daniel Cukier Mar 05 '14 at 14:09
  • 5
    For Rails 3+ you should join relative path, not absolute. Do not prefix config directory with slash. – wst Sep 10 '14 at 11:22
  • 10
    Not sure about previous versions but in Rails 4.1 you can do `Rails.application.config.whatever_you_want = YAML.load_file(Rails.root.join('config', 'config.yml'))[Rails.env]` – d4rky Oct 13 '14 at 08:26
  • This [post](https://coderwall.com/p/8ruh8a/custom-config-for-rails-app) , [post](https://quickleft.com/blog/simple-rails-app-configuration-settings/) can be helpful also.. – Arup Rakshit May 09 '15 at 13:39
  • I find it weird that there isn't a built in way for Rails to manage app configuration. Am I missing something? I should just be able to drop a yaml file in the config directory and then be able to access the settings through a global method. Rails is opinionated in so many other ways but not this. – iphone007 Aug 26 '15 at 21:22
  • `Rails.application.config.whatever_you_want` works for under Rails 3.2.22 as well. If you had yaml with a key `some_key`: `Rails.application.config.whatever_you_want['some_key']` to use it in your app. – dft Nov 22 '15 at 19:06
  • 2
    @iphone007 it is indeed possible to load arbitrary yaml files from the config directory. see [smathy's answer](http://stackoverflow.com/a/28225785/979091) below which in my opinion should now be the accepted answer. – omnikron Jan 05 '16 at 11:47
82

Rails 3 version of initialiser code is as follows (RAILS_ROOT & RAILS_ENV are deprecated)

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

Also, Ruby 1.9.3 uses Psych which makes merge keys case sensitive so you'll need to change your config file to take that into account, e.g.

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

development:
  <<: *DEFAULTS

test:
  <<: *DEFAULTS

production:
  <<: *DEFAULTS
David Burrows
  • 5,217
  • 3
  • 30
  • 34
  • 3
    You don't need `"#{Rails.root.to_s}"`; `"#{Rails.root}"` works. – David J. Feb 13 '12 at 03:57
  • 3
    I recommend `Rails.root.join('config', 'config.yml')` instead of `"#{Rails.root.to_s}/config/config.yml"` – David J. Feb 13 '12 at 03:58
  • 2
    And, instead of APP_CONFIG, I recommend using: `AppName::Application.config.custom` – David J. Feb 13 '12 at 04:03
  • 1
    David, your first two comments are best practice and i'll ammend the code but the last one i'm going to leave out as this means you need to remember to change the AppName every time you use this code. – David Burrows Feb 27 '12 at 16:47
61

Rails >= 4.2

Just create a YAML file into config/ directory, for example: config/neo4j.yml.

Content of neo4j.yml can be somthing like below(For simplicity, I used default for all environments):

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

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default

in config/application.rb:

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

Now, your custom config is accessible like below:

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

More info

Rails official API document describes config_for method as:

Convenience for loading config/foo.yml for the current Rails env.


If you do not want to use a yaml file

As Rails official guide says:

You can configure your own code through the Rails configuration object with custom configuration under the config.x property.

Example

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

These configuration points are then available through the configuration object:

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

Official Reference for config_for method | Official Rails Guide

Ali MasudianPour
  • 14,329
  • 3
  • 60
  • 62
25

Step 1: Create 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)

Step 2: Create config/config.yml

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

development:
  <<: *common

test:
  <<: *common

production:
  <<: *common

Step 3: Get constants anywhere in the code

facebook_key = AppConfig.facebook['key']
twitter_key  = AppConfig.twitter['key']
Omer Aslam
  • 4,534
  • 6
  • 25
  • 24
  • How do we read ENV variable in config.yml, my configuration is the same ..i have added variable in bashrc and im trying to read that in config.yml using key: <%= ENV[URL] %>... this is not working – shiva Jan 25 '17 at 10:29
  • @shiva Look into the Figaro gem for ENV variables. This config setup is for values that do not need to be hidden from source control. – Shadoath Mar 08 '17 at 22:35
17

I just wanted to update this for the latest cool stuff in Rails 4.2 and 5, you can now do this inside any of your config/**/*.rb files:

config.x.whatever = 42

(and that's a literal x in there, ie. the config.x. literally must be that, and then you can add whatever you want after the x)

...and this will be available in your app as:

Rails.configuration.x.whatever

See more here: http://guides.rubyonrails.org/configuring.html#custom-configuration

smathy
  • 26,283
  • 5
  • 48
  • 68
  • 3
    Just a clarification that initially caused a problem for me; the x is not a placeholder for whatever you want to put in, it really needs to be the letter `x`. – tobinibot Aug 27 '15 at 21:01
  • Great point @tobinibot - I've added that clarification to my answer, thanks. – smathy Aug 28 '15 at 16:10
  • Interesting that the guides actually don't mention the 'x', but I can attest that it is still necessary as of Rails 5.0 – Don Jul 29 '16 at 20:34
  • You're right Don, that's weird - I'm sure it used to say it. – smathy Aug 03 '16 at 00:40
  • I hope this saves someone some effort, but to autoload I had to put the config.x stuff in config/initializers/.rb Where myappname is the module name contained in config/application.rb. You then need to do Myappname::Application.config.x.something = 'something' – Andy Fraley Mar 28 '17 at 22:07
  • 1
    From the current rails docs: `You can configure your own code through the Rails configuration object with custom configuration under either the config.x namespace, or config directly. The key difference between these two is that you should be using config.x if you are defining nested configuration (ex: config.x.nested.nested.hi), and just config for single level configuration (ex: config.hello).` Source: https://guides.rubyonrails.org/configuring.html#custom-configuration – David Gay Jan 11 '19 at 22:15
6

Just some extra info on this topic:

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

".with_indifferent_access" allows you to access the values in the hash using a string key or with an equivalent symbol key.

eg.
APP_CONFIG['audiocast_uri_format'] => 'http://blablalba/blabbitybla/yadda' APP_CONFIG[:audiocast_uri_format] => 'http://blablalba/blabbitybla/yadda'

Purely a convenience thing, but I prefer to have my keys represented as symbols.

foomip
  • 574
  • 7
  • 7
5

I use something similar to John for Rails 3.0/3.1, but I have erb parse the file first:

APP_CONFIG = YAML.load(ERB.new(File.new(File.expand_path('../config.yml', __FILE__)).read).result)[Rails.env]

This allows me to use ERB in my config if I need to, like reading heroku's redistogo url:

production:
  <<: *default
  redis:                  <%= ENV['REDISTOGO_URL'] %>
Jack Chu
  • 6,791
  • 4
  • 38
  • 44
  • 2
    I don't think I would need this every day, but this is a really cool solution for those times when you do need it. I think I would change the filename to config.yml.erb though to match rails convention. – Andrew Burns Feb 03 '12 at 19:22
2

Rails 4

To create a custom configuration yaml and load it (and make available to your app) similar to how database_configuration.

Create your *.yml, in my case I needed a redis configuration file.

config/redis.yml

default: &default
  host: localhost
  port: 6379

development:
  <<: *default

test:
  <<: *default

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

Then load the configuration

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

Access the values:

Rails.configuration.redis_configuration[Rails.env] similar to how you can have access to your database.yml by Rails.configuration.database_configuration[Rails.env]

skilleo
  • 2,451
  • 1
  • 27
  • 34
  • You could also save yourself some time by only taking the settings for your current environment, which are presumably the only ones you need anyway: `Rails.configuration.redis_configuration = YAML.load_file("#{Rails.root}/config/redis.yml")[Rails.env]`. However in rails 4.2 and above [smathy's answer](http://stackoverflow.com/a/28225785/979091) is probably a simpler way to go. – omnikron Jan 05 '16 at 11:33
1

Building on Omer Aslam's elegant solution, I decided to convert the keys into symbols. The only change is:

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

This allows you to then reference values by symbols as keys, e.g.

AppConfig[:twitter][:key]

This seems neater to my eyes.

(Posted as an answer as my reputation isn't high enough to comment on Omer's reply)

Kitebuggy
  • 89
  • 6
0

see my response to Where is the best place to store application parameters : database, file, code...?

A variation to what you had in that it's a simple reference to another file. It sees that environment.rb isn't constantly updated and doesn't have a heap of app specific stuff in it. Though not a specific answer to your question of 'is it the Rails way?', perhaps there'll be some discussion there about that.

Community
  • 1
  • 1
Straff
  • 5,499
  • 4
  • 33
  • 31
0

I prefer accessing settings through the global application stack. I avoid excess global variables in local scope.

config/initializers/myconfig.rb

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

And access it with.

MyAppName::Application.myconfig["yamlstuff"]
6ft Dan
  • 2,365
  • 1
  • 33
  • 46
0

My way to load Settings before Rails initialize

Allows you to use settings in Rails initialization and configure settings per environment

# config/application.rb
Bundler.require(*Rails.groups)

mode = ENV['RAILS_ENV'] || 'development'
file = File.dirname(__FILE__).concat('/settings.yml')
Settings = YAML.load_file(file).fetch(mode)
Settings.define_singleton_method(:method_missing) {|name| self.fetch(name.to_s, nil)}

You could get settings in two ways: Settings['email'] or Settings.email

greenif
  • 1,055
  • 1
  • 12
  • 25
0

My best way to custom config, with raise message when setting.yml is missing.

gets loaded from a custom initializer in config/initializers/custom_config.rb

setting_config = File.join(Rails.root,'config','setting.yml')
raise "#{setting_config} is missing!" unless File.exists? setting_config
config = YAML.load_file(setting_config)[Rails.env].symbolize_keys

@APP_ID = config[:app_id]
@APP_SECRET = config[:app_secret]

Create a YAML in config/setting.yml

development:
  app_id: 433387212345678
  app_secret: f43df96fc4f65904083b679412345678

test:
  app_id: 148166412121212
  app_secret: 7409bda8139554d11173a32222121212

production:
  app_id: 148166412121212
  app_secret: 7409bda8139554d11173a32222121212
Marcelo Austria
  • 861
  • 8
  • 16
0

I like simpleconfig. It allows you to have per environment configuration.

Jerry Cheung
  • 1,258
  • 1
  • 12
  • 13