Separate read/write configuration/setup for Rails 7 application - ruby-on-rails

rails 7
AWS Aurora RDS Cluster with one write endpoint and one read endpoint
I would like to configure my Rails application to use one endpoint to write and one endpoint to read for the production environment, and a single endpoint for reading/writing in the test environment.
Reading through the documentation, it seems as what I need to do, is that I need to do the following (assuming a production .
In /config/database.yml:
production:
primary:
database: my_primary_database
username: root
password: <%= ENV['PRIDUCTION_ROOT_PASSWORD'] %>
adapter: mysql2
primary_replica:
database: my_primary_database
username: root
password: <%= ENV['PRIDUCTION_ROOT_PASSWORD'] %>
adapter: mysql2
replica: true
test:
database: my_test_database
username: root
password: <%= ENV['TEST_PASSWORD'] %>
adapter: mysql2
Note: the documentation mentions that the username for the writers and replicas should be different, but the AWS Aurora cluster will not allow me to do that. Is this a recommendation or a must?
And this is what I should have in my /app/models/application_record.rb:
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
if Rails.env == 'production'
connects_to database: { writing: :primary, reading: :primary_replica }
end
end
Then, run the following command:
rails g active_record:multi_db
Which will generate the file: config/initializers/multi_db.rb and inside that file do:
Rails.application.configure do
if Rails.env == 'production'
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
end
end
Am I missing anything, or do I need to add the following to config/environments/production.rb?
config.active_record.writing_role = :default
config.active_record.reading_role = :readonly
Anything else?

Related

Rails - Access Heroku DB from another rails app

I have two applications deployed in heroku which have their own pg database. I wonder is there a way so that one application can have the access to the db of other application without storing values in its own db.
The database.yml looks like this:
production:
primary:
database: my_primary_database
username: root
password: <%= ENV['ROOT_PASSWORD'] %>
adapter: mysql2
secondary:
database: my_secondary_database
username: secondary_root
password: <%= ENV['SECONDARY_ROOT_PASSWORD'] %>
adapter: mysql2
migrations_paths: db/animals_migrate
Your model should have below:
class Order < ApplicationRecord
connects_to database: { writing: :secondary }
end
Please have a look at the below documentation.
https://guides.rubyonrails.org/active_record_multiple_databases.html
I hope this will help you with what you want to achieve.

make rake db:create setup another database besides development, test or production

I'm using rails 4.2 and trying to configure (in a already established application) the Audited Gem following this second database approach.
My config/database.yml file was as follows:
default: &default
adapter: mysql2
pool: 5
timeout: 5000
development:
<<: *default
host: <%= ENV["MYSQL_HOST"] %>
username: <%= ENV["MYSQL_USER"] %>
password: <%= ENV["MYSQL_PASSWORD"] %>
database: <%= ENV["MYSQL_DATABASE"] %>
test:
<<: *default
host: <%= ENV["MYSQL_HOST"] %>
username: <%= ENV["MYSQL_USER"] %>
password: <%= ENV["MYSQL_PASSWORD"] %>
database: <%= ENV['TEST_ENV_DB'] %>
And I intend to make it work for another db, besides development, test or production. However the task rake db:create only creates my development and test database. Is this possible to accomplish in my rails version?
audition:
<<: *default
host: <%= ENV["MYSQL_HOST"] %>
username: <%= ENV["MYSQL_USER"] %>
password: <%= ENV["MYSQL_PASSWORD"] %>
database: <%= ENV["AUDITION_DATABASE"] %>
Note the new name for audition database
if you want to read/write to a seconds database in rails < 6
create a module
module AuditionConn
def self.included(base)
base.class_eval do
if Rails.env == 'development'
establish_connection "audition-development" # database.yml
else
establish_connection "audition-production" # database.yml
end
end
end
end
then include it in any model you want to read/write from/to auditions database
class AuditionDBModel < ActiveRecord::Base
include AuditionConn
end
migration for second database
def up
AuditionDBModel.connection.create_table ... do |t|
...
AuditionDBModel.connection.change_column ...
end
I think you want to create a new environment call audition, Right?!.
Clone an existing environment file for instance, config/environments/test.rb and rename it config/environments/audition.rb
Add a new configuration block in config/database.yml for your environment.
Update any other configuration file you might have under the config folder with your new environment, some gems need to config it.
Now you can start the server
rails server -e audition
I think this may help you:
create another model for audit:
class AuditModel < ActiveRecord::Base
connects_to database: { writing: :audit_db, reading: :audit_db}
end
or
ActiveRecord::Base.establish_connection(
adapter: "mysql2",
host: "localhost",
username: "myuser",
password: "mypass",
database: "somedatabase"
)
for details:
https://guides.rubyonrails.org/active_record_multiple_databases.html
https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionHandling.html

Connection switching to support multiple databases is not working in Rails 6.0.0.beta3 version

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

Passing ENV variables to database.yml in Rails

Here is my database.yml config:
development:
adapter: ibm_db
username: "username"
password: "password"
database: '*LOCAL'
schema: <%= ENV['CA_SCHEMA'] %>
ibm_i_isolation: 'none'
Here is my initializer:
module Ca2eModelExtractor
class Application < Rails::Application
config.before_configuration do
ENV['CA_SCHEMA']= 'XAMDL'
end
end
end
After running rails c I did ENV['CA_SCHEMA'] and saw XAMDL as an output, so it works as expected. But when I run ActiveRecord::Base.configurations, I got a hash, where schema is nil. Any ideas?

Connecting to multiple databases in ruby on rails

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.)

Resources