Chamber lets you source your Settings from an arbitrary number of YAML files and provides a simple mechanism for overriding settings from the ENV, which is friendly to how Heroku addons work.
Add this line to your application's Gemfile:
gem 'chamber'
And then execute:
$ bundle
Or install it yourself as:
$ gem install chamber
The following instructions are for a Rails app hosted on heroku with both staging and production heroku environments.
Create a Settings class that extends Chamber in app/models/settings.rb
:
class Settings
extend Chamber
end
Create a config/settings.yml
that has this structure:
# specify environment your Rails app is running in
development:
# In development, we manually set the value to the variable we'll use
# Settings.REDIS_TO_GO -> returns the URL
REDIS_TO_GO: "redis://root@localhost:6379"
production:
# In production, on Heroku, for example
# Settings.REDIS_TO_GO -> looks for the variable in the ENV and returns its value
REDIS_TO_GO:
environment: "REDISTOGO_URL"
Call source
in your Settings class:
class Settings
extend Chamber
source Rails.root.join('config', 'settings.yml'), namespace: Rails.env, override_from_environment: true
end
Add environment-specific files for development and test to supply the values for those environments. Make sure to add these to .gitignore.
Add another call to source
for these files:
class Settings
extend Chamber
source Rails.root.join('config', 'settings.yml'), namespace: Rails.env, override_from_environment: true
source Rails.root.join('config', "credentials-#{Rails.env}.yml")
load!
end
Finally, after all your source
calls, you must call load!
:
class Settings
extend Chamber
source Rails.root.join('config', 'settings.yml'), namespace: Rails.env, override_from_environment: true
source Rails.root.join('config', "credentials-#{Rails.env}.yml")
load!
end
Use heroku config
to set the ENV_VAR_NAME
value for the staging and
production remotes.
Now you can access your settings in your code as properties of your Settings
class (assuming you extended Chamber in a class named Settings
).
In other words, given a configuration file like this:
s3:
access_key_id: value
secret_access_key: value
bucket: value
the corresponding Paperclip configuration would look like this:
Paperclip::Attachment.default_options.merge!(
storage: 's3',
s3_credentials: {
access_key_id: Settings.s3.access_key_id,
secret_access_key: Settings.s3.secret_access_key
},
bucket: Settings.s3.bucket,
...
Generally this is expressed in this overly simplified form: "Don't store sensitive information in git." A better way to say it is that you should store sensitive information separate from non-sensitive information. There's nothing inherently wrong with storing sensitive information in git. You just wouldn't want to store it in a public repository.
If it weren't for this concern, managing settings would be trivial, easily solved use any number of approaches; e.g., like using YAML and ERB in an initializer.
I recommend adding a pattern like this to .gitignore
:
# Ignore the environment-specific files that contain the real credentials:
/config/credentials-*.yml
# But don't ignore the example file that shows the structure:
!/config/credentials-example.yml
You would then use Chamber like this:
class Settings
extend Chamber
source Rails.root.join('config', "credentials-#{Rails.env}.yml")
end
You should be able to organize your settings files however you like. You want one big jumbo settings.yml? You can do that with Chamber. You want a distinct settings file for each specific concern? You can do that too.
Chamber supports this by allowing:
- Arbitrary number of files:
class Settings
extend Chamber
source Rails.root.join('config', 'settings.yml')
source Rails.root.join('config', 'facebook.yml')
source Rails.root.join('config', 'twitter.yml')
source Rails.root.join('config', 'google-plus.yml')
end
-
Environment-specific filenames (e.g.,
settings-#{Rails.env}.yml
) -
Namespaces:
class Settings
extend Chamber
source Rails.root.join('config', 'settings.yml'), namespace: Rails.env
end
heroku addons are configured from ENV. To support this,
Chamber's source
method provides an override_from_environment
option; e.g.,
class Settings
extend Chamber
source Rails.root.join('config', 'settings.yml'), override_from_environment: true
end
-
Add a rake task for validating environments (do all environments have the same settings?)
-
Add a rake task for setting Heroku environment variables.
I'd love to hear of other gems and/or approaches to settings!
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request