I need to keep some kind of state in my Rails project.
Some kind of global variable or something like that, which has an initial value at the server startup, and could be accessed and modified everywhere in the project. How to do that? What is the best way to achieve it?
Create a file in config/initializers folder and create your global variable there.
# config/initializers/my_var.rb
$my_global_var = 'hello'
But usually there are "cleaner" ways to do this. Global variables are not thread-safe and this is kinda hot topic these days.
I think that the best solution here could be settingslogic gem . You define settings in yaml file and then you can access them anywhere in the code. Read and set them. At the same it enables you to have more than just one 'global variable'. In most of the projects I've worked with, settings weren't changed during the runtime, but if you need that behaviour, you can just do it.
# config/application.yml
defaults: &defaults
my_global_variable: 100
development:
<<: *defaults
production:
<<: *defaults
#And then anywhere in the application you can do:
Settings['my_global_variable'] = 200
Related
I have some constants I am using throughout my app.
I'd say there are three types:
some are really passwords to external stuff like sendgrid login/password
some are internal "secret codes" like devise secret key
some are just what I'd call global constants that is to say there are constants that we use a lot throughout the app and don't want anybody to easily change this. They nearly never change. Some examples: the ID of our facebook page, or the number of deals "per page" we define in our infinite scrolling on the homepage (critical for UX), or the url of our brand-validated logo on aws cdn(present in many view files html.erb and assets javascript .js files). One aspect I also have in mind when asking my question, is that even if they seem less critical than a devise key, for those constants, I would like to gather, to make sure very few people and only authorized developers can change those critical data.
Here's what we do today:
For 1 and 2: I put the constants on config/application.yml
And for 3 : I put the constants on a custom .rb config file as described by official Rails guide (guides.rubyonrails.org/v4.2/configuring.html#custom-configuration)
For example: on /config/initializers/app_custom.rb
Rails.application.configure do
config.x.infite_scrollhp_feed_per_page_deals = 30
end
then it is called in a controller this way:
nb_per_page = Rails.configuration.x.infite_scrollhp_feed_per_page_deals
But each time I am unsure if I should put global constants inside config/application.yml or in my custom config .rb file?
What is the recommended "Rails -way"? How to decide where to put them ? Is there a generally accepted "good-sense"/"proven to be efficient/well-structuring" practice/rule ?
Also is there a different in performance that is to say are application.yml "injected" faster into view (.html) and assets(.js) files when user load a page than if they are defined on my custom config file ?
I would advise using config/secrets.yml for sensitive data (1 and 2):
development:
some_password: ...
test:
some_password: ...
production:
some_password: <%= ENV["SOME_PASSWORD"] %>
This way you can put different settings for different environments (for development, test and production).
And I would highly recommend keeping the production sensitive data in ENV variables.
When it goes for non sensitive data (3) I would put in config/environments/*.rb files when different settings are needed for different environments.
If that's not the case and the setting is the same for all environments, I would put it into application.rb, application.yml or in a custom file in initializers/* or even as class constants.
I have an application that will eventually be open-sourced. Currently it runs on my own domain, but I want to set the domain to be a variable that can be changed. Basically after declaring:
foo = ENV['DOMAIN_NAME'] || 'example.com'
I want to be able to do reference it in:
Views
Configuration
Controllers
Helpers
Optionally: Can i set up a configuration file somewhere that holds all my globally declared variables, and then reference them everywhere? This would allow me to make a config.rb.sample file that I can ask users to fill their settings in.
I'm really happy with a combination of the global gem and the dotenv gem. The first one would be for global configuration, and the second one for storing the environment variables.
Your global .yml files would contain reference to your environment variables (such as the one you put above: ENV['DOMAIN_NAME']) that would actually be defined in your .env file.
You can use Figaro. It's really really good and easy to use. You don't need any configuration for it whatsoever, you add the gem in your Gemfile, bundle and that's it!
To store your variables you need to create a new file in config/application.yml and then store them like:
# Global
#
aws_access_key: ~
aws_secret_key: ~
aws_s3_host: 's3-eu-west-1.amazonaws.com'
rails_secret: 'ce223735d819fb993466ac5e615fff07cc71c19db40e211b83a3ac579203fcf4db78251f4143025e99aabffb1ea46bd252b7b16e50c4c88e5407b42fe5d4e6c4'
devise_secret: '9c1fdc65b9f385c54c99e1a81ea398269749f12eee6790c12921dcf1ba7579864ef0fe40f8bcf33d2d78fcbbb506573f5a0c864090de9f3fd991f8367c2aee7c'
# Per Environment
#
development:
domain: 'lvh.me:3000'
production:
domain: ~
# Puma
#
max_threads: 5
web_concurency: 2
And to access them you simply call Figaro.env.rails_secret or ENV['rails_secret'] :)
More info: https://github.com/laserlemon/figaro
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.
My question is seemingly simple but has been pretty elusive. I want one value that can be called anywhere in the application - it's a minimum value we are using for validations in the model, we want to inform the user of that value, etc.
So far, I have done the following:
In config/initializers, I created a new .rb file (under suggestion I found on another thread):
minimum = 15
and only got that it couldn't be found after starting rails server.
I found a strange suggestion to put the value in en.yml as minimum: 15, same issue as above.
Obviously, application helper and controller won't help as I need the value in my models. I did however find one solution, which was to put it in the class Application in config/application.rb:
config.after_initialize do
::Minimum = 15
end
and afterwards call it like this:
MyApp::Application::Minimum
Obviously, this solution, while it does work, isn't ideal. If I could find a way to alias MyApp::Application::Minimum as just "minimum", I'll be completely satisfied, but getting it done in the initializers is, from what I've heard, a better solution.
You can stick something in a model if you want and call it from anywhere:
Couriers = %w[TNT UPS RoyalMail Bike Hand Pigeon Other]
But I prefer putting them in a yaml file.
Create a config.yml file in your configs directory and put your vars in there:
defaults: &defaults
node_1: '10.8'
node_2: '10.9'
node_3: '10.0'
whatever: 1
thereis: 2
development:
<<: *defaults
playground:
<<: *defaults
production:
<<: *defaults
poststaging:
<<: *defaults
test:
<<: *defaults
Load the config file using something like this in your initializers directory. Create a file in /config/initializers called 'load_vars.rb' and put the following in there:
SETTINGS = YAML.load_file("#{Rails.root}/config/config.yml")[Rails.env]
You'll have to restart your server after changing these though.
-- EDIT --
To use these variables, you can load with something like this from your model, controller, views:
SETTINGS['var_1']
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