Set database based on how the application was started - ruby-on-rails

I have two Rails applications (lets call them APP-1 and APP-2), each of them has a dependancy on a third Rails application (APP-3).
I would like to be able to run the tests for APP-1 and APP-2 in parallel on my CI server. The problem is, both need to start up APP-3 and write to a DB via the APP-3. This causes conflicts and failures if the tests are run in parallel.
My idea for a solution is for APP-1 and APP-2 to each start their own instance of APP-3 and to have each instance point to a different DB. Is there a way to dynamically set the DB in the database.yml of APP-3 so that it connects to a different DB depending on which APP starts it up?
FYI. APP-1 and APP-2 currently start APP-3 via rake tasks.

Make two database.yml files for App-3. Call them database_A.yml and database_B.yml or whatever you want.
In your environment.rb file for App-3, add the following toward the end of the Initializer block.
Rails::Initializer.run do |config|
# ...
# Decide what database_FOO.yml file you care about.
#
db_config_file_name = "database_A.yml" # Put your logic here for choosing which yml file you want.
db_config_file_path = File.join("config", db_config_file_name)
config.database_configuration_file = db_config_file_path if File.exists? db_config_file_path
end
I pulled this from my blog, where I describe how I use a different database.yml file when I launch my app with JRuby. The concept is similar, so hopefully you find this helpful.
http://www.workingasintended.com/2010/05/03/choosing-a-different-rails-databaseyml-file-for-jruby/

Related

How do we run some OS command when Rails is starting?

I need to run a command after or before starting Rails. It will start a server on port 9292 so my chat app will work.
This command should preferably be executed automatically with Rails (on production and development).
How do we do that in Rails 4?
Is Capistrano the only option? Can we schedule it to be executed when Rails starts?
Use capistrano and forman or systemd to manage your chat server instance, like, for example you would do for sidekiq.
A good start would be : http://anlek.com/2015/01/using-foreman-with-upstart-capistrano/
You have 2 options that I know of if you don't want to use Capistrano. In your config/application.rb
config.after_initialize do
# ....
end
http://guides.rubyonrails.org/configuring.html
or you can write a custom initializer that is run with on_server_start event.
There's a whole section of config/ intended for startup behavior: config/initializers/. If you need to do anything as part of the startup of your app, you can create an initializer file here, and it will automatically get run as Rails starts.
To do this, simply create a new file: config/initializers/chat_app.rb:
# This file will start and establish an initial connection to the chat app
`chat-app --some-arg` # <== The chat app
We use this for various startup and system sanity checks for the application. It's independent of your deployment, so if you need it for other deployment purposes, creating a Capistrano (or even Rake) task is the better option.

What is the purpose of this information in a seperate .yml file

I'm pretty new to this and I was curious as to why this information may have been given to me in a separate .yml file to be used on a RoR app.
I assumed that it was info to the put into my bash profile as it has corresponding environmental variables in the app itself.
BASE_URL: 'http://localhost.com:5000'
development:
MAX_THREADS: '1'
PORT: '5000'
WEB_CONCURRENCY: '1'
test:
I'm also curious as to why you would want to set your url differently as the information states.
Thanks a bunch.
I'd think changing the default port a matter of preference unless there's another part of the stack the development team likes to leave running at 3000 by default, for example, a Node.JS server or other projects.
The .yml file you've been given should be picked up when running bundle exec <command>, but not as part of your bash environment variables.

rails app running multiple times on production with different configurations

I want to run the same rails app several times with a few configuration differences on the same server. Each app must have its own:
database
ports
cookie_store key(not sure if needed)
secret_key_base
Let's say I want to run the same code multiple times to service different cities:
newyork.myapp.com and boston.myapp.com. I wonder what would be the best way to store and use the different configurations.
Use environments:
Add a file to config/environments, one for each site you want to host. Name it something along the lines of 'production_[city]', replacing [city] with the city name. Copy the production.rb file contents into each.
in config/database.yml find the 'production' block of yml and duplicate it once for each site you want to host. Rename the root node of each block to production_[city], matching the filenames above. For example:
production_ny:
adapter: mysql2
username: my_user
password: my_pa$$w0rd%&*#
database: production_ny
This takes care of the database settings per app.
Assuming Rails 4, your secret key base will be in config/secrets.yml under an environment node, as per config/database.yml so just add an entry per site:
production_ny:
secret_key_base: xxxxxxxx1111111122222223333333344444444...
All sites will need an end-point. Using a different domain for each would give you separate cookies and sessions for free. Or you could go the subdomain route:
http://guides.rubyonrails.org/configuring.html#deploy-to-a-subdirectory-relative-url-root
tldr:
In your config/environments/production_ny.rb:
config.relative_url_root = "/ny"
for example. Then set up your webserver to handle subdirectories. You may need to add a path to cookies in order to scope them to the virtual directory. Just use:
Rails.configuration.relative_url_root
Ports, again, will have to be set up at the webserver level. (Apache, nginx, etc.)
To see if it all works, try this in the command-line:
RAILS_ENV=production_ny bundle exec rails s
This should start a development style webserver for you to access, but use the production_ny environment.
You will need to create and set up your database as normal - create, migrate, seed.
The final step is setting the RAILS_ENV environment variable to production_[city] per app using your web server. The steps to do this will depend on your technology choice.

Rails: Where to put configuration variables

My team is maintaining a Rails application. The previous developer(s) decided to put some configuration variables (like facebook app id, twitter app id) as env variables. But this is not very versatile. If we have two applications (test and production), we are forced to use only one hardcoded configuration (or changing it manually). Also it is good practice to put these variables in the version control.
Is that the right way to do that? If not, what is the right way?
We are using following solution in 2 apps.
Store config variables in yml files for https://github.com/railsjedi/rails_config gem.
Apps are configured to use different yml files in production and dev modes via initializers.
On production servers directory with yml files are symlinked with 2 apps.
Task for capistrano looks so:
namespace :settings do
task :symlink, roles: :app do
run "ln -s /path_to_settings/#{rail_env} #{current_path}/config/settings"
end
end
after "deploy:create_symlink", "settings:symlink"

Deploying a rails app to multiple locations

I'm trying to deploy the same rails app to two different locations with different app names, different logos, different stylesheets, etc.
I've got the code working based on an APP_NAME and a HOST_NAME variable I store in environments/production.rb. Now I need to actually deploy it, and I need a better solution than manually editing the environment file on the production machine.
The only way I can see to do it is to create a new production environment - e.g. production_app2 - and define APP_NAME and HOST_NAME differently in them. Is there a better way?
No no no! Don't edit the environment files. I mean, edit them as you need to for things that need to be configured the same for every deployment, but not for things that should be configurable between deployments.
For that, use configuration.
Throw a YAML file in config that looks something like this:
development:
:app_name: App 1
:host_name: something.com
test:
:app_name: App 1
:host_name: something.com
production:
:app_name: App 1
:host_name: something.com
Call it whatever makes sense. Let's say settings.yml.
Now load it with an initializer in config/initializers/settings.rb that looks like this:
SETTINGS = YAML.load_file("#{RAILS_ROOT}/config/settings.yml")[RAILS_ENV]
Now access your configuration like this:
SETTINGS[:app_name]
(If you don't want to change your existing code at all, inside config/initializers/settings.rb add lines that set your existing names like APP_NAME = SETTINGS[:app_name], etc.)
Note that this is one possible implementation of settings configuration, but even if another approach is taken it should be based on deployment-independent configuration. This can be much more easily and maintainably set up to persist between deployments and upgrades than mucking with environment files.
Again, to recap:
environment files are for configuration that is the same across all deployments
configuration files are for configuration that can change between deployments
Update
For Capistrano based deployments, this is what I use to symlink multiple configuration files in the new current from the shared directory (I think it originally came from an Ezra recipe from EngineYard):
after "deploy:update_code","deploy:symlink_configs"
namespace(:deploy) do
task :symlink_configs, :roles => :app, :except => {:no_symlink => true} do
configs = %w{ database settings }
configs.map! { |file| "ln -nfs #{shared_path}/config/#{file}.yml #{release_path}/config/#{file}.yml" }
run <<-CMD
cd #{release_path} && #{configs.join(' && ')}
CMD
end
end
I think that's a pretty good way.
Where we are we define different environments (e.g. 'staging', 'production', 'production_backup' - giving us a staging.rb, production.rb, production_backup.rb where you can define your specific APP_NAMEs and HOST_NAMEs) and can deploy to each of them using Capistrano. It works just fine.
This is a good link on it: http://www.egtheblog.com/?p=8
Because you are actually deploying to two different environments, it seems best to create two different environment files, each with their own settings. Make sure you pick descriptive names for your environment files, not just production2.
You could also store this information in the database, but I don't know if you're willing to accept such a dependency. I guess using a database would only make sense if the number of deployments is too large to manage easily with a few environment files.

Resources