Phil Sturgeon
Phil Sturgeon

Reputation: 30766

Accessing config from application.rb in Controller (Rails 3)

I'm trying to add two extra config options to my application.rb so I can read them out in controllers.

# Extra
config.twitter.key = 'foo'
config.twitter.secret = 'bar'

I am trying to access them using three suggested methods:

self.config.twitter.key # Should be extended through ApplicationController Base
config.twitter.key # Inherited but with different syntax
CONFIG['twitter']['key'] #some massive magical array that apparently exists somewhere

They all give me different kinds of error when I pass them through the "debug" method, E.g:

debug self.config.twitter.key # undefined method `key' for nil:NilClass

So, whats going on?

Upvotes: 24

Views: 19352

Answers (5)

Patrick Robertson
Patrick Robertson

Reputation: 2306

I believe you've got a slightly incorrect idea behind what your expectations for the config/application.rb is providing you. The ActiveRecord::Base and ActiveController::Base eigenclasses use the Rails::Application::Configuration class that is configured in config/application.rb. The attributes aren't available in classes that descend from either of the Base classes, nor their eigenclasses. This is why you are running into errors in ApplicationController.

There are generally two ways to make configuration initializations in a Rails app. The first way is to create a configuration module and then load values into it via initializer:

First, create a Twiter Config module:

#lib/twitter_config.rb
module TwitterConfig
  def self.config
    @@config ||= {}
  end

  def self.config=(hash)
    @@config = hash
  end
end

Create a YAML config file:

# config/twitter.yaml
development: &base
  key: "foo"
  secret: "bar"

test:
 <<: *base
 key: "foo2"

production:
  <<: *base
  secret: "barbar"

Alternatively, if you don't intend to add config/twitter.yaml to your SCM, you can just skip this and set the key and secret via environment variables. This would be the suggested solution for an application with a public SCM repository deploying on Heroku.

Then load and set the value via an initializer:

#config/initializers/01_twitter.rb
require 'twitter_config'

TwitterConfig.config = YAML.load_file("config/config.yml")[Rails.env].symbolize_keys

It's generally a best practice to number your initializer files as Rails will load them in order according to their filename. If you are initializing a datastore and that is critical for other steps, then it needs the lowest number. Alternatively, if you are using environment variables, this would be the init file:

#config/initializers/01_twitter.rb
require 'twitter_config'

TwitterConfig.config[:key] = ENV['twitter_config_key']
TwitterConfig.config[:secret] = ENV['twitter_config_secret']

Throughout the Rails application, you now have access to the config values with TwitterConfig.config[:key] & TwitterConfig.config[:secret]. You can include the module as well, just watch out for conflicts.

You can also just load the values as a global constant. It feels a bit ugly to me though:

#config/application.rb
TWITTER_CONFIG = YAML.load_file("config/twitter.yaml")[Rails.env]

Upvotes: 44

brutuscat
brutuscat

Reputation: 3130

I've tried this and seems to be working, you can use ::Rails.application.config.

For example I'm using it to get the correct time_zone set in the application like this:

Rails.application.config.time_zone

I found it thanks to the less-rails code: https://github.com/metaskills/less-rails/blob/master/lib/less/rails/helpers.rb

So you can declare this in your application.rb or in any enviroment file:

config.twitter_key = 'foo'

And then read it like so anywhere in your code:

Rails.application.config.twitter_key

Upvotes: 13

brahmana
brahmana

Reputation: 1326

A small update to the widely accepted answer here : Accessing config from application.rb in Controller (Rails 3)

The methods inside the module TwitterConfig should be class methods (or module methods if you prefer it that way). They can't be instance methods.

Sorry to put this in an answer, but I could not find a way to comment on that answer.

Upvotes: 0

Ingemar
Ingemar

Reputation: 47

Just put a file in config/initializers/ like app_config.rb If you use ENV constant you can later on easily deploy to Heroku setting the values with the heroku config:add twitter_key=mypublickey command.

Something like this:

## config/initializers/app_config.rb
unless Rails.env.production?
  ENV['twitter_key']    = 'foo'
  ENV['twitter_secret'] = 'bar'
end

You keep your production keys out of revision control and don't need to dribble with YAML-files.

Upvotes: -1

David Lyod
David Lyod

Reputation: 1438

You might want to consider using a yaml file approach.

In application.rb

CONFIG = YAML.load_file("config/config.yml")[Rails.env]

In config/config.yml

development: &base_config
    twitter_key = "foo"
    twitter_secret = "bar"

test:
  <<: *base_config
    twitter_key = "foo2"

production:
  <<: *base_config
    twitter_secret = "barbar"

Same usage as before with definable attributes on an environment level with overloading.

CONFIG['twitter_key']

Upvotes: 5

Related Questions