How can we run a ruby on rails application with different database configuration?
in detail: I want to run multiple instance of a rails app with different database config for each on production. How is it possible?
I think you can duplicate the config in database.yml into different environments, like prod1, prod2 ... and then set RAILS_ENV environment variable to match before starting up each respective server...
You can duplicate your database.yml file as DGM mentioned. However, the right way to do this would be to use a configuration management solution like Chef.
If you look at the guide for setting up Rails stack, it includes a 2 front-end Web server + 1 back-end DB server. Which would include your case of duplicating database.yml file.
If you are able to control and configure each Rails instance, and you can afford wasting resources because of them being on standby, save yourself some trouble and just change the database.yml to modify the database connection used on every instance. If you are concerned about performance this approach won't cut it.
For models bound to a single unique table on only one database you can call establish_connection inside the model:
establish_connection "database_name_#{RAILS_ENV}"
As described here: http://apidock.com/rails/ActiveRecord/Base/establish_connection/class
You will have some models using tables from one database and other different models using tables from other databases.
If you have identical tables, common on different databases, and shared by a single model, ActiveRecord won't help you. Back in 2009 I required this on a project I was working on, using Rails 2.3.8. I had a database for each customer, and I named the databases with their IDs. So I created a method to change the connection inside ApplicationController:
def change_database database_id = params[:company_id]
return if database_id.blank?
configuration = ActiveRecord::Base.connection.instance_eval { #config }.clone
configuration[:database] = "database_name_#{database_id}_#{RAILS_ENV}"
MultipleDatabaseModel.establish_connection configuration
end
And added that method as a *before_filter* to all controllers:
before_filter :change_database
So for each action of each controller, when params[:company_id] is defined and set, it will change the database to the correct one.
To handle migrations I extended ActiveRecord::Migration, with a method that looks for all the customers and iterates a block with each ID:
class ActiveRecord::Migration
def self.using_databases *args
configuration = ActiveRecord::Base.connection.instance_eval { #config }
former_database = configuration[:database]
companies = args.blank? ? Company.all : Company.find(args)
companies.each do |company|
configuration[:database] = "database_name_#{company[:id]}_#{RAILS_ENV}"
ActiveRecord::Base.establish_connection configuration
yield self
end
configuration[:database] = former_database
ActiveRecord::Base.establish_connection configuration
end
end
Note that by doing this, it would be impossible for you to make queries within the same action from two different databases. You can call *change_database* again but it will get nasty when you try using methods that execute queries, from the objects no longer linked to the correct database. Also, it is obvious you won't be able to join tables that belong to different databases.
To handle this properly, ActiveRecord should be considerably extended. There should be a plugin by now to help you with this issue. A quick research gave me this one:
DB-Charmer: http://kovyrin.github.com/db-charmer/
I'm willing to try it. Let me know what works for you.
Well. We have to create multiple environments in you application
create config/environmenmts/production1.rb which will be same as of config/environmenmts/production.rb
then edit database.yml for production1 settings and you are done.
start server using rails s -e production1
Related
I have a model called SystemSettings with a name on and a value. It is where I store the majority of my configuration for my app. I need to be able to access it in my production.rb inside my rails 3.2 app. How would you go about doing this?
Since the Rails config such as production.rbis read before ActiveRecord is initialised you would need to use a callback:
Rails.application.configure do
ActiveSupport.on_load(:active_record) do
config.custom_variable = SystemSettings.find_by(name: "Foo").value
end
end
But since the callback executes later when ActiveRecord is ready you can't immediately use its value which is why your approach may be flawed due to race conditions.
Unless you are building something like a CMS where you need to provide a user interface to edit system settings you will be better off using environmental variables. They are immediately available from memory and do not have the overhead of a database query.
http://guides.rubyonrails.org/v3.2.9/initialization.html
I have one rails app and two different databases.
Use Case:
If I browse http://mydomain.com, then it point to one rails app
If I browse http://mydomain.com/project1, then it point to same rails
app with different database let's say project1DB
If I browse http://mydomain.com/project2, then it point to same rails
app with different database let's say project2DB
Both databases are identical in terms of tables and schema
I can achieve this by using establish_connection "project1DB" into model but i don't want to modify my model.
I tried following way into application controller but it didn't work sometimes
before_filter :dbconnect
def dbconnect
if session[:product] == "project1"
ActiveRecord::Base.establish_connection 'project1_' + Rails.env
end
if session[:product] == "project2"
ActiveRecord::Base.establish_connection 'project2_' + Rails.env
end
end
I need to query a 3rd party database which is entirely separate from the Rails 3.2 application I'm building (belongs to a different application which my company uses internally).
Ultimately, I'll be setting up a cron to load new rows from the "other" database which my Rails application will be processing.
I have the access to otherdb set up, and I'm wondering where to go from hereādo I create a new entry in config/database.yml? If so, how do I then specify when a query is to be directed to otherdb, instead of my default Rails development or production db?
There's a few ways to implement this requirement, the easiest of which would be to use config/database.yml and custom namespaced model(s).
Setting up something similar to the below, using a suffix of Rails.env to follow the naming convention will provide the functionality you outlined.
First, create new entries for the external database each of your existing environments. It'll help you to be able to test the functionality.
# database.yml
development:
# add configuration as required
otherdb_development:
# add configuration as required
Second, add a model for each of the specific tables you need to access in the otherdb database. I'd recommend adding a namespace directory for these models (otherdb in the example below) to avoid confusion and potential clobbering:
# /app/models/otherdb
class Otherdb::Foo < ActiveRecord::Base
establish_connection "otherdb_#{Rails.env}"
set_table_name "foo" # customize this if the table name will be different from the classname and is required
end
You can then use (as an example) methods on Otherdb::Foo and use the resulting data as required.
I had the same problem yesterday. Since you are using Rails 3.2, all your models that connect to the external database will have to be subclasses of a single, abstract class that establishes the connection. In earlier versions of Rails, #Sasha's answer would have worked. But in 3.2, that answer will lead you to getting various confusing database errors. (What errors you get depends on what DB you use.)
In Rails 3.2, this is the only way I have found that will work:
Make a common base class for all models that need to talk to a
non-default database.
Tell ActiveRecord that this base class is abstract by calling self.abstract_class = true.
Call establish_connection in the base class.
Here is an example with students and courses from an external table:
# database.yml:
development:
# default configuration goes here
other_development:
# external db configuration goes here
class OtherTable < ActiveRecord::Base
self.abstract_class = true
establish_connection "other_#{Rails.env}"
end
class Student < OtherTable
end
class Course < OtherTable
end
If you'd like more detail, see the blog post I wrote titled Establishing a Connection to a Non-Default Database in Rails 3.2.
With Ruby on Rails, is there a way for me to dump my production database into a form that the test part of Rails can access?
I'm thinking either a way to turn the production database into fixtures, or else a way to migrate data from the production database into the test database that will not get routinely cleared out by Rails.
I'd like to use this data for a variety of tests, but foremost in my mind is using real data with the performance tests, so that I can get a realistic understanding of load times.
You can also check out http://github.com/napcs/lazy_developer which will allow you to put the production data into yaml files.
We just had a similar problem and ended up writing a helper method in rspec that fetches some data (in our case, login details for some accounts) from the production database.
The following should give an idea:
require 'yaml'
def accounts
#accounts ||= lambda {
config = YAML.load_file("#{Rails.root}/config/database.yml")['production']
dbh = Mysql.real_connect(config['host'], config['username'], config['password'], config['database'])
accounts = []
result = dbh.query("SELECT `accounts`.* FROM `accounts`")
while row = result.fetch_hash do
row.delete("id")
accounts << Account.make(row)
end
dbh.close
return accounts
}.call
end
You can use the seed.rb inside the db folder, populate your test database with the data you need. There is nice example available on Railscasts: http://railscasts.com/episodes?search=seed
Would recommend you though to keep your production data away from your testing environments. And do make backups!!!
In my rails application, I have a background process runner, model name Worker, that checks for new tasks to run every 10 seconds. This check generates two SQL queries each time - one to look for new jobs, one to delete old completed ones.
The problem with this - the main log file gets spammed for each of those queries.
Can I direct the SQL queries spawned by the Worker model into a separate log file, or at least silence them? Overwriting Worker.logger does not work - it redirects only the messages that explicitly call logger.debug("something").
The simplest and most idiomatic solution
logger.silence do
do_something
end
See Logger#silence
Queries are logged at Adapter level as I demonstrated here.
How do I get the last SQL query performed by ActiveRecord in Ruby on Rails?
You can't change the behavior unless tweaking the Adapter behavior with some really really horrible hacks.
class Worker < ActiveRecord::Base
def run
old_level, self.class.logger.level = self.class.logger.level, Logger::WARN
run_outstanding_jobs
remove_obsolete_jobs
ensure
self.class.logger.level = old_level
end
end
This is a fairly familiar idiom. I've seen it many times, in different situations. Of course, if you didn't know that ActiveRecord::Base.logger can be changed like that, it would have been hard to guess.
One caveat of this solution: this changes the logger level for all of ActiveRecord, ActionController, ActionView, ActionMailer and ActiveResource. This is because there is a single Logger instance shared by all modules.