Distillery not replacing environment variables - environment-variables

In my umbrella project using distillery for releases, I have a db app config with the following:
config :main, Main.Repo,
adapter: Ecto.Adapters.Postgres,
username: "${DB_USERNAME}",
password: "${DB_PASSWORD}",
database: "${DB_NAME}",
hostname: "${DB_HOST}",
pool_size: 10
As I have set REPLACE_OS_VARS=true in my build, the environment vars are read correctly configures the database.
I have a similar set up in an email app which has the following config:
config :email, from_email: "${FROM_EMAIL}"
I am then looking to access this from inside my email app, like so:
#from_email Application.get_env(:email, :from_email)
But the value of #from_email is "${FROM_EMAIL}" not the environment variable I set for FROM_EMAIL.
I am not too familiar with how distillery works and am unsure how passing in these environment variables in these similar ways is causing it to be read differently.
Insight as to why this may be happening would be greatly appreciated.
EDIT:
We are able to pass the $FROM_EMAIL environment variable in when distillery compiles, but we would like to pass this in at run time.
We are able to do this in the db app, but not in the email app for some reason.

Code directly inside the module definition (i.e. outside def) is evaluated at compile time. You'll need to call Application.get_env at runtime to get the correct value:
Add:
def from_email, do: Application.get_env(:email, :from_email)
to the module and then change all #from_email in the module to from_email().

Related

Rails: configuring applications

I am reading and coding along with a tutorial.
I have an application.yml file with some constants created to hold data. To include those constants in ENV and initialize them at start, this code was given :
config_file = Rails.application.config_for(:application) #this is the bothersome part
config_file.each do |key,value|
ENV[key] = value
end unless config_file.nil?
I fail to fully understand this code. In particular, on the first line, where do the chained objects come from what do they mean and how do I create such on my own ?
It loads data from a config file into the app. The example from the docs about #config_for:
#config/app.yml:
production:
url: http://127.0.0.1:8080
namespace: my_app_production
development:
url: http://localhost:3001
namespace: my_app_development
If you do rails c and type Rails.application.config_for(:app) into the console, you'll get:
{"url"=>"http://localhost:3001", "namespace"=>"my_app_development"}
which is just a regular hash you can loop through using #each or access it's values through keys.

Can't assign an array to a variable in an .ENV file (rails app)

I want to create an array and assign it to a variable in a .env file, like so:
FOOD=["cookies", "grapes", "cake", "pie"]
And then, in a separate seed.rb file, create an instance of an object, like in the example below, and use the "FOOD" array to define an attribute of my object:
User.create(name: "jane doe", favorite_foods: ENV["FOOD"])
This doesn't work. When I seed the database, this instance of User is not created. Help please. I've seen stuff about "php" and "config" files, but nothing explicitly details step-by-step how to achieve this.
I put stuff in my .env that I don't want made visible when I push my app to Github or Heroku. So keep in mind that I don't want the FOOD array visible to any public spaces that will deploy/store my app. Thanks.
I would recommend using Foreman or Dotenv to load environment variables from a .env file. Follow the Rails installation instructions at https://github.com/bkeepers/dotenv.
Here's the catch: as far as I can tell, you can't store an array as an environment variable directly. What you can do instead -- and this is what I do in most of my apps -- is use a comma-separated string, and process it in Ruby.
For example:
# .env
FOOD=cookies,grapes,cake,pie
# seeds.rb
User.create!(
name: "Jane Doe",
favorite_foods: ENV.fetch('FOOD').split(',')
)
This will split the comma-separated string into an array, and use that in assignment.
Using the .create! method (with the !) may help you debug why your instance isn't being created, as it will immediately return validation errors, etc.
Also, using #fetch here will ensure that environment variable is present, and will throw an error if not.
If you wanted the app to fall back to a default list if that environment variable was missing, you could also use:
ENV.fetch('FOOD', 'default,food,list').split(',')
#=> ['default', 'food', 'list']
You need the dotenv gem installed to be able to load the .env environment variables.
https://github.com/bkeepers/dotenv

How do I set a global configuration variable everywhere in rails

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

Setting variable depending upon RAILS_ENV

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.

Rails global state variable

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

Resources