application wide global variable - ruby-on-rails

In Rails, where should I define the variable which can be recognized by every layer of Rails stacks.
For example, I would like to have a CUSTOMER_NAME='John' variable which can be accessed in helper, rake task, controller and model. Where should I define this variable in Rails app?
I am using Rails v2.3.2

In an initializer in /app/config/initializers all .rb files in here get loaded, I usually create one called preferences.rb for things like this.
See: http://guides.rubyonrails.org/configuring.html#using-initializer-files

An alternative approach is to set a key on the config object in config/application.rb, like so:
MyApp::Application.configure do
# ...
config.my_key = 'some "global" value'
end
You can then access my_key from anywhere in your app with just this:
MyApp::Application.config.my_key
Also, Mike Perham has described a similar, though a more comprehensive approach in his blog post.

You want a true global constant? Use ::COSTUMER_NAME.
You want a true global variable? Use $COSTUMER_NAME (discouraged).
You want a request-global variable? Use the Hash in the #env method.

Related

How to use database.yml define json file for each environment

I working on json file format in rails.
I like to use environment in config/databse.yml (or better place) to define what json file to use in the app.
But have no idea, unable to find any sample.
Any help please.
Existing code in helper as follow
def get_table(foo)
get_data = if [:production, :sandbox].include?(Rails.env)
File.read("support/product.json")
else
File.read("support/sample.json")
end
JSON.parse(get_data)
end
If I understand you correctly then you are trying to load a JSON file based on the current environment? I'm not sure a JSON file is really the kind of data store you are looking for... but that is a different question.
In your case, I would use an environment variable to set the file name that is to be used during the execution of the application.
Change the helper to something like:
def get_table
database_content_from_file = File.read(ENV['database_file'])
JSON.parse(get_data)
end
You can now set the environment variable 'database_file' in each of your different types of environments. This can be done by setting a system-wide variable or using a gem like https://github.com/laserlemon/figaro (which I highly encourage you to use).
With this, you could set ENV['database_file'] to 'support/sample.json' in your development environment and set it to 'support/product.json' in production.
I hope this answers your question. If not please rephrase your question in a manner that is easier to understand.

Adding to Rails.application.config before initializers run

I want to inject a custom property (hash map) into my Rails.application.config. It seems that the way to do it is simply to assign a new variable in environment.rb:
Rails.application.config.feature_map = { :email => true }
I need to access this map through various places in my application, like the user model, controllers, and rake tasks.
Other gems, like devise, also need access to this. The problem is that adding it to environment.rb seems to be too early in the application life-cycle.
I have code in initializers/devise.rb like this:
if Rails.application.config.feature_map[:email] = true
The server complains that this field doesn't exist.
I also use it to add additional validation in my user model:
if Rails.application.config.feature_map.enabled?(:username)
validates_length_of :username, :in => 3..50
I also get a runtime error here about undefined feature Rails.application.config.feature_map
Where can I move this so that I can access it as early as in initializers and in my model class? I tried moving it into a new initializers/feature_map.rb file, but that didn't work either.
Put it in config/application.rb:
module MyRailsApp
class Application < Rails::Application
config.feature_map = ActiveSupport::OrderedOptions.new
config.feature_map.email = true
end
end
Anything you set in there will be default for all environments, but can be overridden per environment in config/environments/*.rb.
Gems like Figaro and .env will help you load up your config even before the loading of initializer.rb
Unless there is a strong reason that you wouldn't wanna use environment variables, I would recommend using either of those gems since they are the recommended way of adding your custom configs.
Edit: See Jimmy Cuadra's answer above, which I ended up going with.
I found an alternative solution: this answer to manipulate the order of initializers.
I can rename my initializer to 00_feature_map.rb and it loads first.

Where is a good place to initialize an API?

I wanted to use this api: https://github.com/coinbase/coinbase-ruby and the first step is to initialize the API, like this:
coinbase = Coinbase::Client.new(ENV['COINBASE_API_KEY'], ENV['COINBASE_API_SECRET'])
I was wondering what the best place to put this code is, and how would I access it if I put it "there"? I want this variable (coinbase) to be accessible ANYWHERE in the application.
Thanks!
The answer to this question really depends on your use case and your approach. My geral recommendation, however, is to create a Service Object (in the DDD sense) (see the section named "Domain Objects Should Not Know Anything About Infrastructure Underneath" in that link), that handles all communication with the Coinbase API. And then, within this service object, you can simply initialize the Coinbase::Client object once for however many times you call into it. Here's an example:
# app/services/coinbase_service.rb
class CoinbaseService
cattr_reader :coinbase_client, instance_accessor: false do
Coinbase::Client.new(ENV['COINBASE_API_KEY'], ENV['COINBASE_API_SECRET'])
end
def self.do_something
coinbase_client.do_something_in_their_api
end
def self.do_something_else
coinbase_client.do_something_else_in_their_api
end
end
So then you might do, e.g.:
# From MyController#action_1
if CoinbaseService.do_something
# ...
else
# ...
end
Or:
# From MyModel
def do_something
CoinbaseService.do_something_else
end
To get the service object working, you may need to add app/services to your autoload paths in application.rb file. I normally just add this:
# config/application.rb
config.autoload_paths += %W(#{config.root}/app)
I find this Service Object approach to be very beneficial organizationally, more efficient (only 1 invocation of the new Coinbase client needed), easier to test (easy to mock-out calls to Coinbase::Client), and simply joyful :).
One way to go about having a global variable can be done as similar as initializing redis in a Rails application by creating an initializer in config/initializers/coinbase.rb with:
$coinbase = Coinbase::Client.new(ENV['COINBASE_API_KEY'], ENV['COINBASE_API_SECRET'])
Now, you can access $coinbase anywhere in the application!
In the file config/initializers/coinbase.rb
Rails.application.config.after_initialize do
CoinbaseClient = Coinbase::Client.new(
Rails.application.credentials.coinbase[:api_key],
Rails.application.credentials.coinbase[:api_secret])
end
In place of the encrypted credentials, you could also use environment variables: ENV['COINBASE_API_KEY'], ENV['COINBASE_API_SECRET']
The above will make the constant CoinbaseClient available everywhere in your app. It will also ensure all your gems are loaded before the client is initialized.
Note: I am using Rails 6.1.4.4, and Ruby 2.7.5

How to share constant in different controllers and models and view in Rails 3

What is the best practice to share an global variable
eg: host = test123.com
and I Can use "host" every where ?
I will used it as CONSTANT to show my email in many places,
So I don't want to hardcode my email address everywhere!
Thanks~
I will typically create a file in my initializer directory or add to my environment (devel or production) and declare my variable with caps.
production.rb
SECRET_KEY = "blahblah"
Then across my app, I can reference to this variable by using the ENV
So, in my view, I would type ENV["SECRET_KEY"] or just SECRET_KEY
You should really avoid doing this. That being said, ::HOST = 'test123.com'
I will used it as CONSTANT to show my email in many places,
if you are only using this for display purposes - then consider putting it in en.yml file (and other locale files if desired)
see http://guides.rubyonrails.org/i18n.html#adding-translations
Just check this out http://railscasts.com/episodes/85-yaml-configuration-file . This is the standard way of defining global configurations in Rails app.

How do i define a second environment.rb file in rails?

My default environment.rb is overflowing, and i would like to have a separate file that works exactly the same way. How can I do so?
You're likely adding things to the environment file that should be in an initializer. Check the config/initializers directory for some examples of what to put in there. That should allow you to break things up and make everything more organized.
Rails actually uses eval to load the special environment files such as config/environments/development.rb. This is the code it uses:
eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
You could define a method such as load_more_environment like this:
def load_more_environment(path)
eval(IO.read(path), binding, path)
end
The first argument to eval is just the code you want to load and it will be executed within the current binding. The third argument will be used to report syntax errors in the file.

Resources