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.
Related
I have to move my app data from the old app database to new app database. The table structures are different. I have written the following script.
require 'mysql2'
require 'active_record'
old_database = {
adapter: "mysql2",
host: "localhost",
username: "foo",
password: "bar",
database: "old_db",
socket: "/var/run/mysqld/mysqld.sock"
}
new_database = {
adapter: "mysql2",
encoding: "utf8mb4",
collation: "utf8mb4_bin",
host: "localhost",
username: "foo",
password: "bar",
database: "new_db",
socket: "/var/run/mysqld/mysqld.sock"
}
class Doctor < ActiveRecord::Base
end
Code for reading a single record from old database
ActiveRecord::Base.establish_connection(old_database)
doctor_attributes = Doctor.order(:id).limit(1).offset(offset).first.attributes
ActiveRecord::Base.remove_connection
This is followed by code for conforming doctor_params with new table structure. The code for creating an entry in new database is as under.
ActiveRecord::Base.establish_connection(new_database)
Doctor.create(doctor_params)
The issue is the Doctor object in the last line has attributes of the old database. Am I not handling database connections properly or is there another issue?
I tried the following
ActiveRecord::Base.establish_connection(old_db)
ActiveRecord::Base.establish_connection(new_db)
doctor = Doctor.new #Instance of doctor as per new database
But if I do
ActiveRecord::Base.establish_connection(old_db)
doctor = Doctor.new # instance of doctor as per old database
ActiveRecord::Base.establish_connection(new_db)
doctor = Doctor.new # Still instance of doctor as per new database
Somehow the Doctor model gets stuck with old database.
I solved the problem as under
require 'mysql2'
require 'active_record'
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
class Doctor < ApplicationRecord
old_database = {
adapter: "mysql2",
host: "localhost",
username: "foo",
password: "bar",
database: "old_db"
}
establish_connection(old_database)
end
class NewDoctor < ApplicationRecord
new_database = {
adapter: "mysql2",
encoding: "utf8mb4",
collation: "utf8mb4_bin",
host: "localhost",
username: "foo",
password: "bar",
database: "new_db",
socket: "/var/run/mysqld/mysqld.sock"
}
self.table_name = 'doctors'
establish_connection(new_database)
end
It feels "hackey" and I am sure it is not efficient when dealing with large databases but it is a solution to my crisis situation. My database has around 8000 entries so I am not worried by efficiency consideration.
Try,
Doctor.establish_connection :new_database
Doctor.create doctor_params
with,
# config/database.yml
default: &default
adapter: mysql2
host: localhost
username: foo
password: bar
socket: /var/run/mysqld/mysqld.sock
old_database:
<<: *default
database: old_db
new_database:
<<: *default
database: new_db
encoding: utf8mb4
collation: utf8mb4_bin
I have read the documentation about MultiDb connection switching of Rails 6.0.0.beta3 and implemented this way:
database.yml
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: root
socket: /var/run/mysqld/mysqld.sock
development:
main:
<<: *default
database: r6_multidb_development
main_replica:
<<: *default
database: r6_multidb_development_copy
replica: true
Article Model
class Article < ApplicationRecord
connect_to database: { writing: :main, reading: :main_replica }
end
Both the databases r6_multidb_development and r6_multidb_development_copy have different records, i was expecting when record is created records should inserted on r6_multidb_development Database and when retrieving record it should from r6_multidb_development_copy database. But in both cases when record is inserted and retrieved it is happening from main configuration that is r6_multidb_development database.
I believe write to the database should happen from r6_multidb_development and read should happen from r6_multidb_development_copy. I would appreciate if anybody figure out this issue.
Add following options to your environment config:
config.active_record.database_selector = { delay: 2.seconds }
config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
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 was working with just one database initially but I needed to add the clients other database which is a SQL Server database. I was able to connect but I am running into a few problems.
Original full database.yml
development:
adapter: postgresql
database: martin_development
username: *******
password: *******
pool: 5
timeout: 5000
development_sec:
adapter: sqlserver
host: *******
port: 1433
database: Database1
username: *******
password: *******
I get the following error:
TinyTds::Error (Database 'DATABASE1' does not exist. Make sure that the name is entered correctly.)
If I take out the database name so it looks like this:
development_sec:
adapter: sqlserver
host: *******
port: 1433
database:
username: *******
password: *******
Everything appears to run normal and I do not get any error messages in regards to a database not being found. However, that database does exist on the clients side.
I am confused on how to extract data from my customers SQL Server database. I am trying to follow along with some resources I found so my project files so far are looking like this:
Model (Mssql.rb)
class MssqlBase < ActiveRecord::Base
establish_connection :development_sec
self.abstract_class = true
end
Model(site.rb)
class Site < MssqlBase
end
Controller(sites_controller.rb)
class SitesController < ApplicationController
def index
#sites = Site.all
#hash = Gmaps4rails.build_markers(#sites) do |site, marker|
marker.lat site.latitude
marker.lng site.longitude
end
end
end
database.yml
development:
adapter: postgresql
database: martin_development
username: *******
password: *******
pool: 5
timeout: 5000
development_sec:
adapter: sqlserver
host: *******
port: 1433
database:
username: *******
password: *******
My goal is to start pulling data from the database but as of right now with this look in regards to my file I am getting the following error:
ActiveRecord::StatementInvalid (TinyTds::Error: Invalid object name 'sites'.: SELECT [sites].* FROM [sites]):
So just to recap I need it to read from the 'DATABASE1' but it is saying it does not exist. When I leave it out for some reason it is connecting with the server but I do not know which database. Now I am trying to pull the data but am getting invalid statements. Any help would be appreciated.
You can do this with Rails.
Create this method.
def with_connection(database, &block)
ActiveRecord::Base.establish_connection(database)
yield
ActiveRecord::Base.establish_connection
end
It changes what database your app is connected to, runs the query and then restores it to default. Not sure if thread safe. Using establish_connection on its own, will not revert to original (as your app can only be connected to one database at a time)
Then use:
with_connection :development_sec do
MssqlBase.first # will call development_sec database
end
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