I would like to configure 2 database instances for a certain environment (say staging or production). The default rails new application just provides a single database instance how do I configure 2 database instances.
You can copy and past one of your existing configurations such as development. and rename it as you want so, in the database.yml:
development:
adapter: mysql2
encoding: utf8
reconnect: false
database:
pool: 5
username: root
password:
host: localhost
new_database:
adapter: mysql2
encoding: utf8
reconnect: false
database:
pool: 5
username: root
password:
host: localhost
Then in the models you create for this new connection add the following methods to the model, for example:
class Document < ActiveRecord::Base
self.table_name = "document" # this allows you to hide a non comforming table name behind the rails model it is NOT necessary for establish_connection to work
self.establish_connection "new_database" # notice there is no = when setting this value, strange, I know.
end
Related
I created two rails apps sample and test. There are two databases. users table in sample app with the field report_id refers to reports table in test app.
I want to display the test app data in sample app by fetching the unique_id field. I want to display reports data for a particular user by connecting these two databases.
How can I achieve this in the simplest way?
For rails6, you can provide two connections and specify databases for each connection,
eg
adapter: postgresql
encoding: unicode
username: username
password: password
pool: 5
host: localhost
development:
primary:
<<: *default
database: database1
adapter: postgresql
secondary:
<<: *default
database: database2
adapter: postgresql
and for production environment, you can use database url's like
primary:
url: <%= ENV['DATABASE_URL'] %>
secondary:
url: <%= ENV['SECONDARY_DATABASE_URL'] %>
You can connect to two databases from each rails project:
#config/sabple_database.yml
default: &default
encoding: utf8
adapter: mysql2
port: 5500
development:
<<: *default
database: sample_db
host:
username:
password:
#config/initializers/sample_database.rb
SAMPLE_DB = YAML.load_file(File.join(Rails.root, "config", "sample_database.yml"))[Rails.env.to_s]
#models
class SampleDbBase < ActiveRecord::Base
self.abstract_class = true
establish_connection SAMPLE_DB
end
#models/my_model.rb
class MyModel < SampleDbBase
end
Read more about that. So, then you can create the same models without migration(allows using Reports.find(report_id)).
Also, you can write a query to some database using ActiveRecord::Base.establish_connection and execute.
Thanks to rails 6. multi DB connection will come default from rails 6.
Please use GitHub version of rails. and configure the database.yml:
development:
primary:
<<: *default
database: multiple_databases_development
animals:
<<: *default
database: multiple_databases_development_animals
migrations_paths: "db/animals_migrate"
For more detail please have a look at https://github.com/eileencodes/multiple_databases_demo
I am working on existing rails project and just finished writing some basic RSpec tests for that.
In our database.yml file we have connection to 3-4 different databases and all are either pointing to either production database or staging database.
For testing environment I created a different yml file called database.test.yml and then symlinked it to database.yml file, so that the correct testing databases connections are created.
My database.test.yml looks something like this:
abc:
adapter: mysql2
host: localhost
reconnect: true
username: monty
password: python
database: abc
pqr:
adapter: mysql2
host: localhost
reconnect: true
username: monty
password: python
database: pqr
test:
adapter: mysql2
host: localhost
reconnect: true
username: monty
password: python
pool: 50
database: testing
My problem now is that how can I enforce that other developers/testers use this database.test.yml and not accidentally run the main database.yml file which contains connections to staging and production databases.
EDIT:
To further clarify my question, I have establish_connection in various models that connect to different databases. So I am not sure the earlier suggestions will solve my problem.
Example:
class Abc < ActiveRecord::Base
establish_connection :abc
end
One way I can think of for solving my problem is doing something like this:
class Abc < ActiveRecord::Base
establish_connection "abc_#{Rails.env}"
end
and in the database.yml:
defaults: &defaults
adapter: mysql2
encoding: utf8
username: root
password: secret
abc_production:
database: abc
<<: *defaults
abc_development:
database: abc_devlopment
<<: *defaults
abc_test:
database: abc_test
<<: *defaults
But I am not sure if this the best practice and I really don't feel to change the application code to setup test environment is good practice.
This idea is based on: http://blog.nistu.de/2012/03/25/multi-database-setup-with-rails-and-rspec
Any nudge or pointers towards the correction direction will be greatly helpful.
You could have something, like:
default: &default
adapter: mysql2
encoding: utf8
database: my_db_name
username: root
password: my_password
host: 127.0.0.1
port: 3306
development:
<<: *default
database: xxxx_development
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: xxxx_test
production:
<<: *default
database: xxxx_production
There are many questions and answers regarding the creation of multiple connections to multiple databases in rails:
https://stackoverflow.com/a/7480330/2120023
https://stackoverflow.com/a/6305540/2120023
Example from outside stackoverflow: http://ilikestuffblog.com/2012/09/21/establishing-a-connection-to-a-non-default-database-in-rails-3-2-2/
But I have yet to find a solution that works when using a model that appears in both databases.
If my default db has a table titles and my Other db has a table titles how do I access the other database's Title model?
title.rb:
class Title < ActiveRecord::Base
end
othertitle.rb:
class Other < ActiveRecord::Base
self.abstract_class = true
establish_connection "other_#{Rails.env}"
end
class OtherTitle < Other
end
I can't use the above because I get this error (EDIT: for clarity there is no other_titles table in either db only a titles table -> EDIT 2: If I do create an other_titles table in the Other database, everything works perfectly but that does not help me access the titles table.):
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'other.other_titles' doesn't exist: SHOW FULL FIELDS FROM `other_titles`
I also can't use class Title < Other because I get a TypeError: superclass mismatch for class Title error.
database.yml
development:
adapter: mysql2
encoding: utf8
database: db_dev
pool: 5
username: xxxx
password: xxxx
socket: /var/lib/mysql/mysql.sock
production:
adapter: mysql2
encoding: utf8
database: db
pool: 5
username: xxxx
password: xxxx
socket: /var/lib/mysql/mysql.sock
other_development:
adapter: mysql2
encoding: utf8
database: other_dev
pool: 5
username: xxxx
password: xxxx
socket: /var/lib/mysql/mysql.sock
other_production:
adapter: mysql2
encoding: utf8
database: other
pool: 5
username: xxxx
password: xxxx
socket: /var/lib/mysql/mysql.sock
I found the answer and it is quite simple:
class OtherTitle < Other
self.table_name='titles'
end
Referenced here:
Efficient way to pull data from second database?
and here:
Cannot connect to two postgres databases in rails 3.2.
I have a ruby on rails application working fine and connected to a database. Now i want to connect to a different database from the same application. The data model can be exactly the same. In fact if i connect to the different database the application works fine. However I want to connect to two different databases. Is it possible in ruby on rails?
For multiple database connection, you need to add the following codes to the database.yml file. Here, I am giving the example of connecting two databases from a rails application
config/database.yml
development:
adapter: mysql2
database: db1_dev
username: root
password: xyz
host: localhost
development_sec:
adapter: mysql2
database: db2_dev
username: root
password: xyz
host: localhost
production:
adapter: mysql2
database: db1_prod
username: root
password: xyz
host: your-production-ip
production_sec:
adapter: mysql2
database: db2_prod
username: root
password: xyz
host: your-production-ip
Here I have used two databases for the development and production environment.
Now we need to connect the model to databases. When you are running your application in development and production mode, all the models will be mapped through the development and production db parameters those been mentioned in your database.yml. So for some model we need to connect to other database.
Lets assume that, we have two models User and Category. The users table is in db1_dev and db1_prod, the categories table in db2_dev and db2_prod.
Category model
class Category < ActiveRecord::Base
establish_connection "#{Rails.env}_sec".to_sym
end
Similarly, when you adding the new migration for the second database, need to add following code to it.
class CreateRewards < ActiveRecord::Migration
def connection
ActiveRecord::Base.establish_connection("#{Rails.env}_sec".to_sym).connection
end
def change
# your code goes here.
end
end
Hope it will work for you :) .
Use establish_connection to switch to a different database:
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "myuser",
:password => "mypass",
:database => "somedatabase"
)
You can also pass a preconfigured environment from database.yml like so:
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['other_env'])
You can also set it for a specific model:
MyClass.establish_connection(...)
You might like to note that as of Rails 6 (2019), Rails has support for multiple primary databases!
https://guides.rubyonrails.org/active_record_multiple_databases.html
The database.yml file will now look something like this:
development:
primary:
database: primary_db
user: root
primary_replica:
database: primary_db
user: ro_user
replica: true
animals:
database: my_animals_db
user: root
migrations_path: db/animals_migrate
animals_replica:
database: my_animals_db
user: ro_user
replica: true
And then it's as simple as specifying in your model files:
class AnimalsModel < ApplicationRecord
self.abstract_class = true
connects_to database: { writing: :animals_primary, reading: :animals_replica }
end
class Dog < AnimalsModel
# connected to both the animals_primary db for writing and the animals_replica for reading
end
(These examples were taken from this helpful tutorial.)
I used this command to create an app rails new guestbook
then i used :-
rails generate scaffold Person name:string
and in routes.rb i unhashed the root :to => 'people#index'
then I wrote in the address bar localhost:3000/people and I got the following error :-
ActiveRecord::ConnectionNotEstablished
ActiveRecord::ConnectionNotEstablished
Rails.root: /home/rudraksha/rbtest/gbook
please answer ASAP
Anyways, the problem is that, connection is unable to establish with database.
Have you configured you database.yml as per you database? If not you have to configure it first.
If you are using mysql, you have to install mysql gem by adding it to your gemfile and running bundle install and configure database.yml accordingly.
Example of database.yml with mysql:
development:
adapter: mysql
encoding: utf8
reconnect: false
database: <db_name>
pool: 5
username: <your_mysql_username>
password: <your_mysql_password>
host: localhost
production:
adapter: mysql
encoding: utf8
reconnect: false
database: <db_name>
pool: 5
username: <your_mysql_username>
password: <your_mysql_password>
host: localhost