Using application-wide variables in Ruby on Rails
Rails offers various ways to implement methods, but implementing global variables is not as straightforward. Currenly, there are several approaches.
Constants
One Solution on Stackoverflow is to put them in config/application.rb
as follow:
module MyAppName
class Application < Rails::Application
MY_CONSTANT = "test"
end
end
It is fine, but that breaks the entity of the file. Since custom global variables meaning custom business logic, it would be better to put them into a separate file.
Global Variables
Global variables are defined with the dollar sign `$`. It can be as easy as:
$my_variable = 4
However, global variables are usually considered an anti-pattern. Mainly because it has no context, and it is mutable. Mutable global variables in a multi-threading application would create race conditions. Variables should be scoped properly, and using global variables means that we want a specific variable to be shared in the application.
Some alternative approaches:
Constants
If the variable is immutable, use constants. It provides the context that this variable is immutable.
class Calculator
DEFAULT_MULTIPLIER = 5
end
Class or instance variable
Another alternative is to use class or instance variable to store such variables:
class Calculator
@@default_multiplier = 5
def self.default_multiplier
@@default_multiplier
end
# optional
def self.set_default_multiplier(n = 5)
@@default_multiplier = n
end
end
It provides the benefit of having a clear namespace (and context). Also, it adds an extra layer of flexibility to modify the variable. It also allows a lock mechanism if this variable is mutable in the application.
Gem figaro & simpleconfig
Another method is to depend on gems. Both Simpleconfig and Figaro offers a good way to configure variables in a different logic. I didn't use simpleconfig before, but I did use Figaro, which is quite handy.
Basically, Figaro creates an config/application.yml
file and you store variables for different environments like:
development:
key: "ad69caf9a44dcac1fb28"
secret: "83ca7aa160fedaf3b350"
test:
key: "ad69caf9a44dcac1fb28"
secret: "83ca7aa160fedaf3b350"
And retrieve the variables like:
Env['key']
It somehow simulates the way we manage variables in Bash or Zsh, which I don't think is neat and straightforward.
Using initializers
Rails loads all files in config/initializers/
folder, which is a good place to init application-wide variables here. For instance, we can create a file business.rb
under the initializers
directory:
module Business
class Logic
Here = "hello world"
end
end
Business::Logic::Here
# => 'hello world'
Filename and module name can be anything. I suggest use something directly related to the business logic as the module name, like your company name or what. It offers better understanding when reading the code.
Thus you can use it anywhere, in controllers, for example:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def set_logic
@logic ||= Business::Logic::Here
end
end
or in any file in the project.
One bad thing is that we have to restart server at any change in this file since it is only 'initialized' at server start.
However, using initializers ensure the scope of different variables are in the same class, and we can create different files, modules, and classes for variables in different scopes. I believe this is the best way to manage application-wide variables so far.