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?
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]
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
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']
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.
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.
Related
I have an initializer named _settings.rb that looks like this
class Settings < Settingslogic
source "#{Rails.root}/config/application.yml"
namespace Rails.env
end
My application.yml defines a value for a custom setting I call environhost.
I call it using:
Settings.environhost
This works fine, EXCEPT for when I try to call the value in my /app/config/application.rb
config.action_controller.asset_host = Settings.environhost
For this, I get an uninitialized constant.
Is there anyway I can put a pointer in my application.rb to load _settings.rb before
config.action_controller.asset_host = Settings.environhost
is loaded? What's the best way to do this?
http://guides.rubyonrails.org/initialization.html
Rails own configuration will be always loaded before any custom things, that's for sure. Otherwise can you imagine what a mess :)
The solution is not to try to load before Rails configuration. Instead, hook into initializer to add your own logic to override Rails default.
Railtie is the place you can do that without sweat. Here you can access config method shared in all initializers including Rails.
module MySettings
def self.environhost
"foobar"
end
class MySettingsRailtie < Rails::Railtie
config.action_controller.asset_host = MySettings.environhost
end
end
Side note: In most cases you should be fine to set assets host as mu_is_too_short commented. If you need anything other than that, you can use custom intializer by Railtie.
I am new to Rails and come from a ColdFusion background, where we would store global / site-wide variables in the 'application' scope. This persists the variable across any view or controller. Does Rails 4 have an equivalent functionality for this type of thing?
The site-wide variable won't typically change often so it doesn't need protecting in any way.
For example, in my situation, I want to store the website's domain name. One for testing and one for live environments. Localhost for development and xxxxxx.com for production.
Any tips or pointers would help. I have Googled this extensively and solutions seem to be far too complicated to achieve what seems to be such a trivial task. What's the best elegant solution for Rails 4?
The simplest, basic and default way is to use the Rails.application.config store.
Rails.application.config.my_config = 'foo'
You can assign a config in your environment:
# application.rb
module MyApp
class Application < Rails::Application
config.my_config = 'foo'
end
end
and read it with
Rails.application.config.my_config
# => 'foo'
This approach works well for very simple applications, but if you want something more advanced there are several gems available.
I'm currently using SimpleConfig. The main advantages are:
per-environment configuration. You can configure default configurations for the application, then override defaults with environment specific configurations
local.rb file for custom overrides
capistrano-like configuration style
it works nicely with the dotenv gem, very useful to avoid storing sensitive credentials in your repo.
This sounds like a perfect example for configuration values stored in config/environments/production.rb and config/environments/development.rb. Just store any value there:
config.my_special_value = 'val'
And access it in your application like this:
Rails.application.config.my_special_value
Always the value of your environment is active.
If you just want to have a „global“ value, store it in your application controller. All your view controllers are derived from your app controller, so you can save any value there as an instance or class variable:
class ApplicationController < ActionController::Base
MY_CONSTANT_VALUE = "foo"
end
class MyViewController < ApplicationController
def index
raise MY_CONSTANT_VALUE.inspect
end
end
You also could implement an helper:
# app/helpers/application_helper.rb
module ApplicationHelper
FOO = "bar"
end
# app/controllers/foo_controller.rb
class FooController < ApplicationController
def index
raise FOO
end
end
I can recommend good method to store variable. I use this on production
Passwords can be stored easier to .env file
like this
#Root dir create file ".env"
PASSWORD=123456
and load password
#Somewhere in app
ENV['PASSWORD'] #=> 123456
it works I hope will help you
You can use gem figaro
write your variables in config/application.yml
HELLO: world
development:
HELLO: developers
production:
HELLO: users
Then you can fetch
ENV["HELLO"]
In rails there is gem named as
gem 'dotenv-rails'
By using it we can assign the variables to system level and used in application.
By using simple steps
First create a simple filed in system level at any place with named extension .env
//in application.rb
require 'dotenv'
Dotenv.load('path-of-your-file.env')
And restart your application
Source
Please got the link for the desscription of dot env gem
This is my current controller : 'trace_controller.rb'
rule_oms = Rule.new("localhost","root","","oms_local")
rule_warehouse=Rule.new("localhost","root","","warehouse_local")
rule_payment=Rule.new("localhost","root","","payment_local")
...
....
We have 2 different modes - Staging and Production. They have Hostname, Pwd, User, Database name which are unique.
How can I change these settings from environment.rb? Can you set variables depending upon them?
Depending upon environment, I get the hostname, pwd, user, db_name for all the different databases. Unlike most Rails app, I connect to several databases irrespective of the environment.
Any ideas what I should be doing? (Using latest version of Rails).
in config folder --> environments --> add another file with your environment name
by default, development.rb, , test.rb and production.rb are present.
add lets say qa_1.rb for your qa_1 environment.
Set your required config in this file, you can copy it from any of the existing environment files and change them as needed.
run your rails app with RAILS_ENV=qa_1
it will take the config from qa_1.rb file
you can set probably settings_logic gem, to set envirornment wise values
gem 'settingslogic'
Then in app/models/settings.rb add
class Settings < Settingslogic
source "#{Rails.root}/config/application.yml"
namespace Rails.env
end
and in /config/application.yml
set you environment specific data
defaults: &defaults
db: default_db
development:
user: dev_user
test:
user: test_user
production:
user: prod_user
db: prod_db
qa_1:
user: qa_1_user
db: qa_1_db
in database.yml also you can use
qa_1:
db: qa_db
user: user
I'm not sure what you're trying to achieve but if you place this in environment.rb, then I can only guess that you want some sort of global constant. If this is what you want, I suggest you create a file inside config/initializers called constants.rb then place the following there.
RULE_OMS = Rule.new("oms-#{Rails.env}")
RULE_WAREHOUSE = Rule.new("warehouse_#{Rails.env}")
RULE_PAYMENT = Rule.new("payment_#{Rails.env}")
then just call RULE_OMS anywhere in your app.
This is what worked for me -:
1) Creation of local.rb in config/environments (Simply a copy of development)
2) Defining the parameters for local in database.yml
3) Setting parameters in config/environment.rb
if Rails.env.local?
OMS_HOST="localhost"
OMS_DB="oms_local"
OMS_USER="root"
OMS_PWD=""
WAREHOUSE_HOST="localhost"
WAREHOUSE_DB="warehouse_local"
WAREHOUSE_USER="root"
WAREHOUSE_PWD=""
PAYMENT_HOST="localhost"
PAYMENT_DB="payment_local"
PAYMENT_USER="root"
PAYMENT_PWD=""
end
if Rails.env.development?
OMS_HOST="amt.com"
OMS_DB="oms_staging"
OMS_USER="user1"
OMS_PWD="xyz"
....
.....
4) In the trace_controller.rb, I used these constants to initialize my Rule model.
5) Add this in the .gitignore file, if you are using it.
6) Don't forget to restart the server.
Apologize for the way my question was framed as it was pretty unclear. Hope this answer will help somebody in the future.
I was wondering how to add custom configuration variables to a Rails application and how to access them in the controller?
Secondly, I was planning to have S3 support for uploads in my application, if I wanted to add a yaml file with the S3 access, secret key, how do I initialize it in my Rails App and how do I access the values that I have defined in that config file.
In Rails 3, Application specific custom configuration data can be placed in the application configuration object. The configuration can be assigned in the initialization files or the environment files -- say for a given application MyApp:
MyApp::Application.config.custom_config_variable = :my_config_setting
or
Rails.configuration.custom_config_variable = :my_config_setting
To read the setting, simply call the configuration variable without setting it:
Rails.configuration.custom_config_variable
=> :my_config_setting
UPDATE Rails 4
In Rails 4 there a new way for this => http://guides.rubyonrails.org/configuring.html#custom-configuration
Update 1
Very recommended: I'm going with Rails Config gem nowadays for the fine grained control it provides.
Update2
If you want a quick solution, then check Jack Pratt's answer below.
Although my original answer below still works, this answer is now outdated. I recommend looking at updates 1 and 2.
Original Answer:
For a quick solution, watching the "YAML Configuration File" screen cast by Ryan Bates should be very helpful.
In summary:
# config/initializers/load_config.rb
APP_CONFIG = YAML.load_file("#{Rails.root}/config/config.yml")[Rails.env]
# application.rb
if APP_CONFIG['perform_authentication']
# Do stuff
end
In Rails 3.0.5, the following approach worked for me:
In config/environments/development.rb, write
config.custom_config_key = :config_value
The value custom_config_key can then be referenced from other files using
Rails.application.config.custom_config_key
In Rails 4
Assuming you put your custom variables into a yaml file:
# config/acme.yml
development:
:api_user: 'joe'
:api_pass: 's4cret'
:timeout: 20
Create an initializer to load them:
# config/initializers/acme.rb
acme_config = Rails.application.config_for :acme
Rails.application.configure do
config.acme = ActiveSupport::OrderedOptions.new
config.acme.api_user = acme_config[:api_user]
config.acme.api_pass = acme_config[:api_pass]
config.acme.timeout = acme_config[:timeout]
end
Now anywhere in your app you can access these values like so:
Rails.configuration.acme.api_user
It is convenient that Rails.application.config_for :acme will load your acme.yml and use the correct environment.
This works in rails 3.1:
in config/environment.rb (or in config/environments/.. to target a specific environment) :
YourApp::Application.config.yourKey = 'foo'
This will be accessible in controller or views like this:
YourApp::Application.config.yourKey
(YourApp should be replaced by your application name.)
Note: It's Ruby code, so if you have a lot of config keys, you can do this :
in config/environment.rb :
YourApp::Application.configure do
config.something = foo
config.....
config....
.
config....
end
Since Rails 4.2, without additional gems, you can load config/hi.yml simply by using Rails.application.config_for :hi.
For example:
touch config/passwords.yml
#config/passwords.yml
development:
username: 'a'
password: 'b'
production:
username: 'aa'
password: 'bb'
touch config/initializers/constants.rb
#config/initializers/constants.rb
AUTHENTICATION = Rails.application.config_for :passwords
and now you can use AUTHENTICATION constant everywhere in your application:
#rails c production
:001> AUTHENTICATION['username'] => 'aa'
then add passwords.yml to .gitignore: echo /config/passwords.yml >> .gitignore, create an example file for your comfort cp /config/passwords.yml /config/passwords.example.yml and then just edit your example file in your production console with actual production values.
Rails 6 and 7
Many outdated answers, so adding one that is specific to Rails 6.
Application specific configuration goes in initializer files. Details are here: edge guides
Example:
config/initializers/foo.rb
module MyApp
class Application < Rails::Application
config.test_val = 'foo'
end
end
Alternatively:
Rails.application.config.test_val = 'foo'
This can now be accessed as:
Rails.configuration.test_val
Many more possibilities.
edge guides #custom-configuration
ex, you can also set up nested namespace configurations:
config.x.payment_processing.schedule = :daily
config.x.payment_processing.retries = 3
config.super_debugger = true
or use config_for to load entire custom config files:
config/payment.yml
production:
environment: production
merchant_id: production_merchant_id
public_key: production_public_key
private_key: production_private_key
development:
environment: sandbox
merchant_id: development_merchant_id
public_key: development_public_key
private_key: development_private_key
Then load it with:
config/initializers/load_payment.rb
module MyApp
class Application < Rails::Application
config.payment = config_for(:payment)
end
end
I just wanted to update this for the latest cool stuff in Rails 4.2, you can now do this inside any of your config/**/*.rb files:
config.x.whatever.you.want = 42
...and this will be available in your app as:
Rails.configuration.x.whatever.you.want
See more here: http://guides.rubyonrails.org/configuring.html#custom-configuration
Check out this neat gem doing exactly that:
https://github.com/mislav/choices
This way your sensitive data won't be exposed in open source projects
I created a simple plugin for YAML settings: Yettings
It works in a similar fashion to the code in khelll's answer, but you only need to add this YAML configuration file:
app/config/yetting.yml
The plugin dynamically creates a class that allows you to access the YML settings as class methods in your app like so:
Yetting.your_setting
Also, if you want to use multiple settings files with unique names, you can place them in a subdirectory inside app/config like this:
app/config/yettings/first.yml
app/config/yettings/second.yml
Then you can access the values like this:
FirstYetting.your_setting
SecondYetting.your_setting
It also provides you with default settings that can be overridden per environment. You can also use erb inside the yml file.
I really like the settingslogic gem. Very easy to set up and use.
https://github.com/binarylogic/settingslogic
If you use Heroku or otherwise have need to keep your application settings as environment variables, the figaro gem is very helpful.
I like to use rails-settings for global configuration values that need to be changeable via web interface.
Something we've starting doing at work is the ActiveSupport Ordered Hash
Which allows you to define your configuration cleanly inside the environment files e.g.
config.service = ActiveSupport::OrderedOptions.new
config.service.api_key = ENV['SERVICE_API_KEY']
config.service.shared_secret = ENV['SERVICE_SHARED_SECRET']
I would suggest good approach how to deal with configuration in your application at all. There are three basic rules:
change your configuration not a code;
use configurations over conditions;
write code that means something.
To have more detailed overview follow this link: Rails configuration in the proper way
If I have some config for web admin to set e.g. number of post per page, some enum showing choice. How should I keep this settings in db ? Should I serialize it and save as blob.
Thanks,
I using rails and I want it to dynamically change this setting through web interface, so I think environment.rb would not fit this situation. So I should have a extra table with two tuples as name, value ?
Most languages/frameworks have a config file of sorts. such as the web.config in ASP or the environment.rb files in RoR. You could use one of these.
Or failing that have a key value pair table in your database.
If you're wanting to do this dynamically through the website I would definitely go for the key value pair table.
For the dynamic config values, you should create a model called Configuration with keys and values. I generally have multiple value columns (for number, string, and date) and then call the appropriate method for the configuration.
For "enums" you should create lookup tables with foreign key relationships to where they attach. For example if you have a Post model and you want an enumeration of Category, you should make the Post belong_to :category and Category has_many :posts.
Use a YAML file. YAML is way simpler than XML.
Make a file called "config.yml" in "config" directory. And load the file using YAML::load(). You can make a setting for each environment by naming the first level as environment (e.g., production, development, test).
See this episode of RailsCasts for details.
If you are using asp.net you can use the Web.Config file.
See Asp .net Web.config Configuration File
You could to create a single table in your database to store key-value pairs.
This is what I use. Got the idea from elsewhere, but the implementation is mine. Pulled from a production project of mine:
class AppConfig
# Loads a YAML configuration file from RAILS_ROOT/config/. The default file
# it looks for is 'application.yml', although if this doesn't match your
# application, you can pass in an alternative value as an argument
# to AppConfig.load.
# After the file has been loaded, any inline ERB is evaluated and unserialized
# into a hash. For each key-value pair in the hash, class getter and setter methods
# are defined i.e., AppConfig.key => "value"
# This allows you to store your application configuration information e.g., API keys and
# authentication credentials in a convenient manner, external to your application source
#
# application.yml example
#
# :defaults: &defaults
# :app_name: Platform
# :app_domain: dev.example.com
# :admin_email: admin#example.com
# :development:
# <<: *defaults
# :test:
# <<: *defaults
# :production:
# <<: *defaults
# :app_domain: example.com
#
# For example will result in AppConfig.app_domain => "dev.example.com"
# when Rails.env == "development"
#
class << self
def load(file='application.yml')
configuration_file = File.join Rails.root, 'config', file
File.open(configuration_file) do |configuration|
configuration = ERB.new(configuration.read).result
configuration = YAML.load(configuration)[Rails.env.to_sym]
configuration.each do |key, value|
cattr_accessor key
send "#{key}=", value
end
end if File.exists? configuration_file
end
end
end
AppConfig.load
Create config/initializers/app_config.rb and paste the above code into it. I'm going to make this into a gem. I figure other people will find it useful.
EDIT: Just saw you wish to edit the config as the app runs via a web based interface. You could do this with this method as both getter and setter methods are defined for each attribute.
in your controller:
def update
params[:configuration].each { |k,v| AppConfig.send "#{k}=", v }
…
end
I don't find a model is the right solution here. Forget about the DB overheard, the idea of being able to instantiate something that controls app configuration doesn't make sense. What's more how you implement it? An instance for each tuple?! It should be a singleton class.